The Ebonheim Chronicle

Development Blog for Chronicles IV: Ebonheim

Yesterday was the 4th anniversary of the 1st commit of the 4th codebase trying to create Chronicles IV. As is tradition, here's a blog post!


Couple of Updates

Warp Point

This blog is now a part of Warp Point!

Wes Fenlon & Matt Sayer have developed a new blog directory collecting gaming-related RSS feeds from around the internet in a really slick user interface calling back to the old days of webrings. You can absolutely lose some hours surfing these feeds!

There's a widget that will randomly show other warp point blogs but I can't get it to work because I think writefreely disables script calls, so until I sit down to hack the guts, you'll have to settle for a button in the post signatures here. Widget works now, scroll down!

Playtesters Welcome

As stated in a few social media posts, I'm still welcoming all offers to playtest the upcoming Dungeon Milestone. Those interested can contact me in any of various ways including email! After some testing from people I've talked to directly, there will be a wave of testing that goes to the Discord server. Discord is totally optional, I'm not requiring any testers to use it, but there will probably be playtest discussions there from at least a few people!

The Dungeon Milestone

I had delusions of having this ready to ship yesterday but it needs to cook a little longer. I have a little running gag going for myself where I keep telling people it'll be done soon or this year or what have you. Anyway, it'll be done soon, or at least this year!

The milestone is a huge leap forward from Oct 2023's Combat Milestone, with a focus on dungeon crawling and the main core game loop! It's a vertical slice of a lot of different features that is meant to feel like a standalone game but it is very much not the opening hours of the final product by any means.

I wrote about the rough plan for this milestone after the previous playtest ended. I'm happy to say that I stand by everything I said then, except for maybe the “this one will come together rather quickly!” part.

Four Years is a Long Time

I definitely remember thinking after the first year that I had probably 2 years of development left. I also remember being pretty sure at the second year that I had about another 2 years left. Four years was, for whatever reason, a marker of a reasonable amount of spare time to spend on a hobby video game.

Sometime before the 3rd birthday I really began to be honest with myself about the scope and time and unreliability of progress. Parts of the game I hand-waved away as “and then I'll just add this” had more understandable costs attached to them, measured in months, and the possible completion dates blurred.

I had to really grapple with this because I always told myself that I didn't want a forever project. I used to look at all the decade+ long hobby games in development and think “at least that's not me!” but here we are staring down the barrel of half a decade and I honestly can't say when it will be done!

All Things in Perspective

The advantage of a solo hobby project is there's no financial risk for anybody for it to take as long as it needs. I don't employ anybody who needs to be paid, I have separate income already and so the timing or success of the end-product doesn't factor much into the work. This is a luxury a whole lot of people working in games simply do not have!

I don't bring this up to gloat or talk down or dismiss by any means, I say this to remind myself that the stakes for my fun hobby are so desperately and incredibly low. In the end, nobody is going to end up homeless because of my slow and wholly unreliable pace.

Just about every year of this project has had full months, sometimes multiple, with zero progress. It happens, and it's somehow something that I've broken my brain into not being bothered about anymore. Sure I'd love to be further along, love to be able to tell people it's out soon, love to be able to write more blogs about more features and show off more gifs and all the rest. But if I get upset about that, or depressed, or anxious, well, I'm throwing away the advantages of being in this position in the first place.

My happy place is making progress on my game and occasionally writing about it, it's something I legitimately enjoy. Even when it's super hard technical problems or refactors, all of it is still something I look forward to! I own all my own tools, all my own code, all my asset creation. I think that really personally helps keep the frustration levels down. It's just so fun to be able to be creating something.

I feel a little like a broken record but for my own sake I often need to say out loud “Be proud of what you've done, look forward to getting to do more, and it'll be done when it's done!”

I would, for the record, rather not be working on this game forever, and my focus is always revolving around a desire to eventually finish something but when will that be?

Well, probably another two years and I'll have it licked.

Thank You

As always, a huge thank you to everyone who has shared in this space for the last four years. I feel very grateful to have gotten to meet and interact with so many kind and talented people!

Wishlist Chronicles IV: Ebonheim! 🌐   🙋‍  

I made a little manifesto for manifesto jam. Fair warning that it's a little needlessly aggressive. I was egged on I think by some of the other entries being a little needlessly aggressive. Just, like, in a silly way.

A wide range of feelings have befallen me since contributing to the jam, both reading other entries and reading the various reactions which vary between critiquing other entries or critiquing the entire endeavor. There are a lot of opinions! So it goes.

Something that stood out to me out of all the comments was someone suggesting that all these manifestos sure seem to point at a lack of places to communicate such thoughts. This mini-manifesto-meta-manifesto has wormed its way into my head and refuses to dislodge.

The following views expressed are my own and do not represent the views of the Chronicles IV: Ebonheim development team despite being its one and only member.

I got into all of this gamedev blogging stuff out of a desire to share my tools and process and designs and ideas. I've always wanted a place to do that, write about the nitty gritty decision making of a big coding project, and cohost was a really nice place to dump that.

That place felt, at least at the start, that it had this shared dissatisfaction with platforms and websites. There was this community punk vibe that made you feel that you were safely surrounded and read by people that loosely agree on at least one metric. I quickly found a great group of folks chasing the same tech writing sharing as I and enjoyed a period of great friendmaking and connection.

Back in those days (Not Actually That Long Ago) the idea of ever actually finishing my game, let alone selling it for money, was pretty far away from my focus. It started as a bit of a toy, something I would fiddle with in the evenings and make a little progress on. Working on the game in some ways became a means to posting. I really did just enjoy not only getting feedback and reactions and conversations from people but then taking that energy on into other peoples projects. It was honestly so fun.

With the transition to Mastodon there has been a real shift. I love all my elephant website mutuals!🐘💕 For what its worth it is still my favorite place to talk to developers about development, but the vibes are very different. The shorter-form responses and twitter-style threads move the needle closer to the microblogging problems and certainly make it harder to have conversation. There is still, in my experience, a great energy there for boosting, sharing, commenting, respecting other peoples feeds, etc.

The fediverse userbase is split into two main camps: people trying it out, investigating what all the fuss is about, trying to stick within their existing friend circle, swept along in some recent migration, and then there are the lifers who have set up their hermit huts on the rocks of decentralization to peer out suspiciously over the shifting sands.

Recently, it has felt quieter on Mastodon than before, which some attribute to some of the population moving on to the butterfly website or back to twitter. I imagine this comes as no surprise to the lifer group who have no doubt seen many such peaks and valleys pass them by.

So it was and so it shall be.

The other websites are really rough! The energy certainly exists in places like Bluesky to form deeper professional connections between developers and share and support one another, but the platform and format directly contradict it. Bluesky is primarily about trying to come up with a pithy 300-character joke about the current discourse or else trying to have the flashiest development gif for other game developers to see. While I've made great connections with some lovely people, I feel I can't interact with them in any meaningful way. We like each others gifs and we leave little jokes.

I've engaged in this! I'm part of that problem. I hate it. But who can blame us?

Everyone is trying to sell something because the stakes are so, SO high for so many people. The fuse has never been shorter and the screws never tighter and if we don't spend at least half of the post character limit hedging and acknowledging that, the Discover Feed is going to Come For Us.

We all log in and try to share the most important thing or console the sad reactions or crack a joke about the thing about the thing about the thing. Every game developer needs to get eyeballs on their work, they have to, it is that or it is ruin. I'm not being facetious, I really do believe that for many it is that dire, that important, that essential.

And it reinforces, every day seems worse, every day a new bit of news, a new revelation, lives are being destroyed in front of our eyes and if its not our lives its easy to feel like it may be us next or we feel survivors guilt. The overwhelming spiral pulls us in and then at the center some random asshole or, hell, a close mutual, posts a goof or tells you you're overreacting or not considering all viewpoints or thinking about it the wrong way.

Posters madness is desperately wanting to help or correct or chide or boost or contribute or console or commiserate and finding no 300 characters will fit into the polygonal spheroid matrix of opposing perspectives.

A chaotic soup of well-meaning people fighting over the best way to help.

I sat back this morning, exhausted, and said “I'm not coming here anymore, I need a break.” and it made me wonder what I even wanted there in the first place. Game Marketing™? Community™? Wishlists™?

I thought about how much I like this blog and tried to interrogate why that is.

This is a place safe from Opinions, and Takes, and Posters Madness. This blog is where I go to write wholly inarguable (until today) things made inarguable by being outputs from my own work and experience. Here is where I can write about a neat thing I did or made that I thought was neat that I want to share because how I made it might be interesting to others.

It's absolutely my escape.

It's a place I can shut the blinds to the outside horrors and just share my hobby with others who enjoy said hobby.

All of the entries in the manifesto jam are saying something their submitters felt like they couldn't sufficiently communicate with their existing platforms. I don't hardly agree with all of them, but there is a sort of cohosty energy there of people feeling safe around like-minded posters. “We're all mad as hell so let it out.” is a powerful feeling and it binds people together.

Maybe there's room, somewhere, for long-form discussions of weird tech stacks or unique development strategies. Maybe there can be a place where the vibe is sharing instead of marketing, maybe such a place exists and I'm not on it, maybe someone will make one and it will come and go, subsumed by capitalism and the horrors.

I don't have a meaningful way to conclude this ramble. But I will continue sharing my silly work and trying to show it to you.

My toxic anxiety is that there's probably an infinite number of uncharitable reading of this post and I guess that's inevitable. I can't construct a post that is immune to that.

I can't do it in 300 characters, 300 posts, or 300 manifestos, and I'll just have to deal with that.

Wishlist Chronicles IV: Ebonheim! 🌐   🙋‍  

I wrote about Chronicles` action system ~sigh~ over three years ago.

With this system, every ability in the game could be defined in-asset and then generically compiled into an easily-reproducible set of game state changes which made simulation and preview trivial.

I then spent months figuring out how to get my NPCs to use them smartly and eventually emerged with a functional behavior planner that has over the intervening years grown into a true cornerstone of the game I'm building.

Through this system, NPC's can plan inventive turn decisions completely dynamically with whatever stats and abilities they have access to. As it has matured, it's become clear that this is a major pull for the game because the enemy units are consistently killingsurprising me with their actions.

It's also been a bugbear and constant pain to keep running and scaling as the game's content has grown and so I blacked out on nyquil for two weeks and rewrote it. Let's talk about it.

Part 1. What Are We Doing Again?

The ultimate end goal for the enemies in Chronicles is for them to kill you very effectively. This is of course their goal, but also, like, my goal for them ♥

A difficulty I faced had to do with all of the abilities in the game consisting of lists of arbitrary actions and target requests such that you cannot, programmatically, understand what an ability “does” or what it's “for.”

So we want our NPCs to take their health and stamina and equipment that they have, analyze their place in the world with what abilities they have available to them, and decide what they should do on their turn that maximizes their ability to kill you very effectively.

But since they can't know from staring at them what any of their abilities actually doooo, the only way to know if a wait is better than moving left or better than throwing the barrel on their right into the doorway behind the player is to fully simulate those actions in a virtual copy of the game state and then analyze the result state to see if they did good.

How the Old System Worked

I'm sometimes asked if my game's behavior is “expert systems” or “goap” or whatever other trendy behavior model people have heard of and I rarely know a succinct concise way to respond. At the risk of being overly reductive, I could say

I fully simulate every possible combination of decisions across 3 turns, score the resulting game states, and pick the best path.

If that sounds brute force and simple, it kind of is! The fact that I can arbitrarily copy my game state thousands of times performantly allows me to just bulldoze into the best solutions. It's heavily optimized and uses the magic 'fast-for-free' feature called C++ so even the Emscripten web build has little trouble discovering the right answers.

It works exceptionally well because of how varied the game gets. Hundreds or thousands of unique equipment and abilities still just plug into this system because they're just action lists at the end of the day and the resulting game state is what is being scored.

What game states are “best” is determined by a series of weights for different things I want them to pursue or avoid. Damaging your primary target is worth points, damaging health is worth more than damaging stamina, using a cooldown costs points, being far away from your target costs points, etc. I can tune these weights with overrides for different actors to make archers maintain distance or for certain fun enemies to ignore friendly fire, etc.

The simulation branches on every turn into a shared leaf-node pool and just continues to pop the next highest node and simulate the next turn off of it to build more nodes. Shockingly complicated actors can just evaluate 1-2 thousand end-nodes, often-times exhausting the graph entirely, and give us the best answer. If I wanted to stop iterating early, most likely due to a performance budget (more on that later) then this becomes I guess you might call a “Best-First Search of Simulated End-States” where hopefully we've explored a good answer by the time we bail out.

The Problems

In general it's worked really well and when I add a new enemy with a new ability and it just starts using it how I imagine they should it all feels really worth it. I'm sometimes really surprised by their tactics and find it challenging and fun to deal with.

Most of the difficulty of using this system over the last couple years has been a death by a thousand cuts of tweaking weights. You see a skeleton doing something silly, you dig into how they came up with that, make a change to the scoring to fix it, and then 2 months later you find out an encounter somewhere else you haven't tried in a while started acting silly as a result.

It's a bit of a gordian knot of tugging and pulling and never feeling very confident that you didn't just break something else. It's at best annoying and at worst depressing. I often doomspiral over the possibility that the whole thing is eventually going to collapse under its own weight as I continue to add content and features to the game.

Performance

More recently, some new enemies I created that I've had designed for a while started really bringing the behavior calc to its knees, pausing and stuttering the framerate every turn struggling to get through all the simulations in time even in Release. I mentioned in the last section that the algorithm is capable of bailing out early with the best-scored node found up to that point but prior to this year I hadn't had a reason to ever cap it.

Consider some value I that represents how many nodes I can process in a turn before it starts affecting the framerate. A sufficiently high I would mean I could always exhaust the full 3-turn graph for any combination of states and still be performant on mediocre hardware. The faster I process nodes, the higher it goes, so I can increase I by optimizing the hell out of the iteration code to push it higher.

After a month or two of increasing I by some 40x, I came to a new roadblock existential to the implementation. I had split the node processing to run over multiple frames because no processing is taking place while the animations for the turn are happening. Unfortunately, some single nodes would suddenly spike the frame time all on their own. This is because the act of just simulating all the possible result states for a particularly complex actor was producing thousands of possible states for just one turn. The combinatorial explosion of considering all their abilities and all their multiple choices was taking too long. Since I couldn't break it up any more granularly than that I began to admit that my plan wasn't going to work long term.

Even for the case of setting an iteration cap and relying on best-first, if a single turn calculation in this system spikes hard like that the cap is worthless for making the calculation performant. Trying to chase I is useless when one big node is able to reduce it to 1.

Part 2. The Multi-Armed Bandit

I accidentally did the thing where I wrote way too much for too long but if you're still here following along, welcome! We're going to talk about some machine-learning data science problems because it's relevant to the new system but let me preface that no, the game's not using LLM's or Generative AI.

Hovering quietly just outside the all-encompassing sphere of LLM's and technofascism is the great data science work being done with reinforcement learning. It's an option to explore with your data if you're interested in solving real problems and generating useful insights that are real and align with reality. Neat! I am but a tiny fish in the sea of this discipline but what's relevant to us here is the Multi-Armed Bandit Problem.

MAB is this idea that you are standing in front of a bunch of slot machines at a casino and each one has some different unknown probability for payout. You pull an arm and it hits 7's and gives you money. For all you know that machine has a 100% reward rate. You pull a different machine and get nothing. 0%.

Over time, you can start to get better guesses at which arms have better probability by trying them over and over and recording the outcomes. If you could infinitely pull every slot arm you could eventually know the probability for the best slots within an acceptable error.

But the unfortunate problem here is that you have to put money in the machine to pull it. You have a finite amount of money which creates a literal budget for how many machine arms you can pull.

So what arms should you pull in what order to maximize the total rewards before you go broke? Do you try them all an even amount (exploration)? Or do you mostly focus on the ones that you feel are rewarding more often (exploitation)? Some mixture of the two? As you pull arms, you're updating your own model for what your expected reward of each arm is, and that's reinforcement learning!

Chess

This doesn't only apply to greasy gambling. Take a game of chess. There are 20 legal first moves for white to start the game. If you have no idea how to play chess, each of those 20 moves has an equal chance of moving you toward an eventual win. Being as your opponent has autonomy, the outcome of your decision can be effectively pseudorandom. As you play more games and get better at it, you are building a model in your head for not just what moves are more reliable at the start but what moves are better in what situations.

A tricky bit with chess is that determining for sure which of the 20 moves is most often the best requires playing out the whole game to see who won. After black moves you're now in one of 400 possible games, and the next time it's white's play you're in one of 200,000 possible games. Chess is extremely large so building out an exhaustive tree of possible game states can become computationally expensive.

So let's pretend that the NPC actors in Chronicles are all pieces in a very strange game of chess. On their turn they have a set of possible moves, they want to pick the best one in their goal of effectively killing the player, but they also want to explore future turns such that they may be able to identify and execute a longer strategy against the player.

The Monte Carlo Tree Search algorithm is designed to tackle this sort of problem. It aims to smartly build the possibility tree by selectively expanding leaf nodes. Rather than brute-forcing the entire tree and walking it, it tries to decide which branches to explore further based on this overall multi-armed-bandit idea of weighing exploration against exploitation.

The basic flow of the algorithm is 4 steps:

  1. Selection: From our given node, select a suitable child node and advance into it
  2. Expansion: If we have unexplored potential children, expand one and advance into it
  3. Simulation: Simulate the game forward from here for a score
  4. Backpropagation: For every node in the chain leading from root to here, increment the fact that we visited them along with how well the simulation scored

Every time this function runs, it expands the graph a little bit and also modifies rolling averages on the predecessor nodes with how well their subtrees are doing. Every time a node is visited, it is able to expand its possible children, which may hurt or hinder the parent's mean score, which in-turn affects whether it's selected to be visited in future iterations.

The subtree branches that consistently produce garbage are quickly ignored, and the ones that have occasionally produced promising results are given more priority, and this is infinitely recursive all the way down to the final decisions of the final turn.

Given a set budget for number of searches, we can rely on this algorithm to do as little simulation as possible while still finding a really good answer.

True Monte Carlo does simulation using rollouts of often random possible outcomes. Chronicles is fully deterministic so our simulation is as well, but an RPG with a lot of RNG could use this same system.

The Chuckster

Let's go over the Chronicles enemy that was causing so much trouble with the old system: The Chuckster. The chuckster has 3 abilities:

  • Wait: Earn extra stamina and skip the turn
  • Move/Attack: Move into an cardinally-adjacent tile, attacking if occupied. 4 possible target options: up, down, left, right
  • Chuck: Throw a nearby actor to a target position, damaging the area around them. Two-Part targeting:
    • Select an actor cardinally or diagonally adjacent: 0-8 possible choices
    • Select an empty tile between 2 and 9 tiles away via Manhattan distance (a diamond): ~80-120 choices

Theoretically, the total possible permutations for 3 turns of this character quickly reaches into the hundreds of millions. What we would like to do is be able search this tree a fixed number of times, expanding it as we go, such that by the end of the search budget we have done the fewest necessary expansions and found the best answer.

  1. Start by creating a root node for the state of the game right before it's chuckster's turn to act
  2. Root has 3 possible nodes to advance to as defined by the 3 abilities available
  3. Each ability node can expand into the possible choices that can be made. Wait has 0, Move/Attack has 0-4, Chuck has 0-8
  4. For cases where an ability has multiple target requests their next potential child set is the next set of possible decisions, some 80-120 in this case
  5. Once a node results in a completed valid turn, it gets 1 child node for the start of the next turn from that state and begins all over again with 3 abilities available to expand into on turn 2

Monte Carlo's first 10-20 searches will quickly expand all 3 abilities, and quickly visit all 4 Move/Attack children, and at least a few of the leaf nodes for Chuck but we are headed toward a problem.

Maybe the best answer for our Chuckster is to throw the nearby boulder at the player. Well, we immediately run into an issue because we have to consider that the searches are selectively expanding child nodes based on how well the average subtree is behaving. If throwing the boulder at the player is the only good use of Chuck out of the hundreds of possible options, what if our first 5,10,20 visits to Chuck don't include the player's position in it's second target request? In this case, Chuck can whither on the vine because it would be too expensive to exhaust all possible options and Move/Attack is providing great stable improvement on strategic positioning and eventually damage inflicted turn after turn and that's where the algorithm will spend its visits.

For help with this we're going to visit the selection and expansion portions of our Monte Carlo.

UCT

I mentioned that Monte Carlo has a “Selection” phase where it chooses a suitable child node, but what does that mean? Is it just the child with the highest average score? Here's where we have an opportunity to implement the MAB strategy of mixing exploration and exploitation.

There's a ton of complicated math around this and it all goes completely over my head, but one of the accepted functions for selecting children in an optimized way is UCT: Upper Confidence Bounds applied to Trees. Simply put, this function mixes the number of parent visits against the node's visits with the actual mean subtree score and applies an 'exploration constant' (C) which leans the selection more toward either exploring new nodes or exploiting good nodes.

It's got a lot of logarithms and square roots and such but it plugs into an implementation of MCTS pretty simply. After experimenting with different C values, it does a great job of giving nodes a chance to prove themselves. Actors in Chronicles can easily be given modifiers to their exploration constant to modify how much of their thinking budget they spend exploring less-obvious paths.

UCT makes it possible for our Chuckster to get a lot of visits to the Chuck ability node even if it's not immediately providing value. In a sense, we're hoping that it is visited enough to find the one good throw that then moves a huge majority of future visits to exploring it.

Progressive Widening

Meanwhile, in the expansion phase, the simplest implementation will always expand one child every time the parent is visited. For cases with very large possibility sets however, this can start to swamp the children set. Progressive widening is the idea of using some constant to limit how often a child is expanded from the possible set.

It's based on visit counts, such that 0-10 visits may produce the first 10 children, but it will start to take more visits, 20-30, to get the next 10 children.

This kind of works against our chuckster because it's now a little harder to mine for the good throws, but! In the case that the good throw is found early, this will prevent a lot of wasted children to be produced as we start visiting the good throw hundreds of times to look for good 2nd turns!

Now if only we could

Try to Find the Good Throw Earlier

Given gestures at everything in the enormous blog post we can't really know at an action level if one decision is better or worse than another. If I have a tile-pick target request with 150 possible 2D positions to choose from, I can't reliably say 'try these first` with any certainty because, well, that's the point of all of this.

But we could maybe do some zhuzhing to try and help it out. Simply put, the parent node has a single list of 2D coordinates and when it expands a child it grabs the next one and makes a child node. So what we could do is order the possibility list when the parent gets created and try help it hit better hits earlier in expansion.

First things first is just taking the location of our primary target and popping it right to the top, or the closest possible tile to our target's position. Let's face it, 99% of the work we're trying to is to do what? effectively kill the player and it's a safe bet that if our first child is aimed straight at our kill target we're going to generate some value.

But that's not always the case, there's support abilities, healing, escape mechanics, distancing, all sorts of reasons not to try and aim at the player, and that's fine, we're probably going to be getting at least a few early visits and that's just the first, after that we want to order the remaining positions in somewhat of an evenly-distributed order.

It's not really helpful to grab 10 children from a set of 200 if those 10 are all clumped in the upper left because it's some positionally-ordered list, we're not exploring at least 75% of the space and we're likely to drop the whole node in favor of things offering value. If the list was organized such that the first 10 items were evenly spaced throughout the total space, and then next 10 were in a slightly denser formation, etc, then every visit would be checking a more representative view of the overall area available.

We can accomplish this in one of two ways:

  • Random! A simple fisher-yates shuffle on the set would reduce to an effectively even distribution more often than you'd think!
  • Furthest-Point Insertion: This N^2 function simply inserts the next point whose closest distance to any already-inserted points is the largest among potential candidates. First point is the primary target, next point is the furthest possible from the target, 3rd point is the furthest possible from the other 2, so on and so forth, this creates a nice even distribution that might help maximize coverage of space explored by early visits.

You could take this one step further and actually branch this decision node a second time. The idea being that given a decision at point X, it is assumed that 0-10 possible nearby choices are similar to the result of picking X and may be worth refining. It might be something I try!

Part 3. Does It Work

Yes!!! All of my test combat scenarios that I've built over the years have passed with flying colors.

  • Bomberman Enemy who puts down a bomb in your direction and then kicks it at you
  • Swapper who swaps you into a group of enemies
  • Swapper swapping you into deep water to drown you
  • Chuckster throwing a boulder not just to hurt you but to seal the escape route behind you
  • Archers using escape teleports to get into better range to shoot you

And the stress tests are now just trivial. Actors have a maximum search budget of 1000 but they rarely reach it. There's a futility check early in to see if they are struggling to find anything better than waiting to early out, and there's an improvement gate to ensure that their best possible turn is slowly growing as they iterate.

I talked before about increasing I by 40x and that is really paying dividends here because the number of game state copies and turn simulations has dropped precipitously within this system. I can even let some actors plan more turns ahead and never come close to spiking the frame time.

The biggest advantage to this new system is feeling like I have far greater control over it. I already feel like my behavior weights are more directly driving the action, I can modify things like the exploration constant and turn lookahead and widening factors to make actors “dumber” or “smarter” and chiefly of all, I don't have to worry about any combination of abilities tanking the performance.

The worst case scenario of too large of a problem is just that the actor won't be able to find the most effective uses within their budget, never that the frame time spikes.

In Conclusion

I suppose I can't call this true Monte Carlo because the simulation is fully deterministic, so maybe you could call the new system UCT-guided simulation tree search or some nonsense but there you have it!

Two weeks of reinforcement learning....learning to arrive at a system that I'm really proud of. Who knows, maybe someone someday can ask another would-be gameplay programmer if their NPCs use “Chronicles planning”.

If you managed to get through this whole thing, please don't hesitate to drop a comment on Bluesky or Mastodon! I'd love to hear your feedback!

Wishlist Chronicles IV: Ebonheim! 🌐   🙋‍  

I was recently doing a modicum of work on the home server backend to limit how often my poor little laptop was being hammered by bots and so I was staring at nginx logs all day and it reminded me that a few of you out there have this blog on your cool and fancy rss readers and so this post is dedicated to my lovely rss fans.

Where's the next playtest milestone??

I really need to stop making public time estimates. I was well on my way last fall, even having a little closed progress playtest with friends, when I was hit with a lot of very important and obnoxious responsibility and it completely locked down my home coding bandwidth. Normally I split my coding brain between work and home but it was all on work for 4 months so I was engaging in self-destructive behaviors like playing WoW Classic.

After the holidays, my first bit of work back was Dungeon Puzzle Sweeper which is proud to be a part of the wildly successful No ICE in Minnesota charity bundle which has raised $630,000 for the Immigrant Law Center of Minnesota! DPS crossed 10,000 browser plays last week and I'm still so happy to see people enjoying that little project!

Now that things have settled down and normalized some, I've gotten some really great momentum built back up on Chronicles and it's moving right along. The last big stretch of work was performance improvements.

YouTube

The game has a YouTube account now where I am experimenting with, umm, modern lines of communication. I've mostly been posting gameplay shorts and it will likely be receiving some form of the same dev gifs everywhere else gets. So tell your nieces and nephews to subscribe!

Something you may be interested in is that I've created a playlist of songs for the OST over there and will continue to fill that out as I make them. These all use the The Big Chronicles Audio System

Discord

It's linked around various places but there is a Discord for the game. That place would theoretically become a lot less quiet when more open testing and demos happen but in the meantime if you're looking to have the cute chron4 skeleton in your sidebar I can provide that.

Thank You for Reading!

I think the key limiting factor to not posting here more often is that I have to copy images to the fileserver and cant paste them directly into writefreely, but that's more reason I suppose to do more text posts.

As a little treat, here's a gif of using a self-push ability on an archer to kite and keep distance, which I think is very cool!

Wishlist Chronicles IV: Ebonheim! 🌐   🙋‍  

Happy new year! It's 2026, this blog was quiet last year, and I released a video game last month, so let's talk!

It's been 3 weeks since the the official itch.io launch of Dungeon Puzzle Sweeper! This has by far been my most visible and successful game launch on itch which was very new for me, so I wanted to do a little debriefing about the development of the project and post-launch statistics!

Development

My last mention of this project was last June when I had already moved on from it. I had built out the game and had it running on the web browser hosted on my own site but it was incomplete, needing some new art assets, and I was itching to get back to Chronicles so I shelved it for the rest of the year.

How it started was that I was obsessed with Daniel Benmergui's Dragonsweeper and it being very UI-based it caught my eye as something I could probably build using the Chronicles EGAUI system. I'm at least a little bit of a minesweeper weirdo and so I got a prototype working in an evening

Generating the Board

The Dragonsweeper board has a lot of rules that determine how the board gets generated. Learning these is part of the game so spoilers ahead!

Click here for Drasgonsweeper spoilersThe lich always spawns in a corner, the slime mage always spawns surrounded by 8's on an edge, the dragon of course spawns in the center, gargoyles spawn in pairs facing each other. Additionally, in v1, one of the two vision orbs always spawned with 1 heart nearby, and there's a lot of rules to try and ensure certain characters don't spawn next to each other.

The first way one would think to implement this is to just loop over all your stuff that you want to add to the board and, for each one, search the board for all the possible spots it's allowed to spawn in and pick one randomly. This works but has problems.

The big issue here to me is computational complexity, which even for a simple game, caused the board generation to take up to 1 second. The reason for this is that every unit being placed needs to iterate over every currently-placed unit to determine their placement rules in relation to the unit you're processing, which in turn iterates over all placed units related to it, etc. You quickly hit N^2 on this.

The other problem is that depending on the complexity of the rules and how many free squares you get, it's not hard to generate a partial board where the rest of the units can't be placed. You might try to shuffle existing ones around to make the rest of the units fit, but depending on implementation you're either going to create an unreliable board that doesn't have all the units every time or you're going to be throwing away gens and retrying a fair amount.

Dragonsweeper v1 had (has?) these issues, even so far as the possible final 100% score not being reliable due to possible generation bugs.

Now, I don't think this slows that game down in the least, it's an exceptionally good and fun video game, but it did get my brain on the kick of trying to improve the generation.

Waveform Collapse

This very trendy and cool sounding thing is popular around procgen enthusiasts and used in a lot of great projects. I'm a novice at all of that but to me it more or less came down to propagating restraints.

The gist of the algorithm is that, given a series of events, which all have constraints for occurring:

  1. Execute the event with the most constraints
  2. Reevaluate the constraints of the remaining events
  3. Repeat until all events have occurred

By always executing the most-constrained event first, its possibility space is maximized, and the interrelated constraints (A depends on B occurring first, B's possibility of occurring relies on how A occurred, etc) which potentially constrain future events propagate downwards. This aims to ensure that the least-permissive events are allowed to occur while the most-permissive events don't clog the space.

The way I applied this theory to dragonsweeper is such:

  • Every tile that will be placed has a set of possible tiles it can be spawned in.
  • Each tile type has a lambda for generating the initial set (dragon only has 1, lich starts with the corners, etc)
  • Each tile type has a lambda for updating the current set based on the last tile placed (gargoyle was placed in a corner, remove it from the lich's set of available places)

From here it is very simple! Find the tile with the fewest possible spaces they can spawn in (spoilers, it's the dragon first), pick a random tile from that set, place it onto the board, and then communicate that that tile type was placed at that position to the remaining tiles so they can update their availability sets.

Next comes the lich who only has 4 places it can spawn, then likely the slime mage who is running shorter on edge pieces, etc. A gargoyle getting placed will communicate to its partner that it's availability has reduced to just 1-2 spots (either side) which shoots it up to spawn next, and so on and so forth:

The only tricky bit from all this is backtracking. Inevitably, you will have randomly painted yourself into a corner and your most-constrained next tile will have 0 possibilities.

The board being trivially copy-able helps here because I simply stored a copy of the board at every step! If I encounter a tile with 0 possibilities I can now:

  1. Roll back the previous tile decision
  2. Remove the decided position from that tile's possibilities
  3. Re-roll for a new position and continue!
  4. If I rewound and removed the last possibility for that tile, well, just recurse backward again!

Putting it Together

The algorithm for the board is now:

  1. Create a list of tiles, each using their type to create an initial set of possible positions
  2. Find the tile with the fewest possible spaces
  3. If the tile has 0 possibilities: a. rewind the board to the previous decision b. remove that decision from that tile's possibilities c. if 0 possibilities, go to a
  4. Select a random tile from the possible set and place the tile
  5. Send the placed tile type and position to the remaining tiles so they update their possible sets
  6. If there are remaining unplaced tiles, go to 2

Building for the Web

After playing with the UI and board generation, what I really wish I had from Dragonsweeper is a way to play it in bed on my phone! The original game ran in landscape mode and wasn't very playable on touch screen. This sent me down a long windy road of trying to get the game running in Emscripten

A few things made this achievable:

  • The Chronicles Engine uses very few 3rd-party libraries, and virtually none outside of ImGui and SDL2
  • The rendering is all software-side, with one simple OpenGL call to output the final EGA-like framebuffer

I had been using zig for building my game on other platforms and that is where I started, but I hit a brick wall of lacking documentation or examples to make it happen. I like my cross-compiling zig build but trying to get it to do emscripten was a bit maddening. There's an empscripten visual studio plugin, but I was having trouble getting it to do anything useful as well.

In the end, perhaps out of frustration, I employed the Mighty Makefile!

CXX = em++
CC  = emcc

all: $(TARGET)

$(TARGET): $(OBJS)  $(MAKEFILE_DEP)
	@mkdir -p $(@D)
	cp $(DEPLOY_FILES) $(BIN_DIR)
	$(CXX) $(COMMON_FLAGS) $(LINK_FLAGS) $(OBJS) --shell-file em_files/em_shell.html -o $@ --embed-file em_deploy@assets

It was an interesting project! I had to learn very quickly a lot of web tech things that I only had passing knowledge of. One of the silly things was just SRGB being applied twice so everything was rendered dark.

It took a week or two of wrestling with, (suddenly being in 32bit was a particular struggle) but before I knew it I was just playing my engine, with my art, my sound effects, my music, running on my renderer, my waveform generation, it all worked!

I immediately threw it up on my personal site and linked it around and within the day there were other dragonsweeper fans sending me bug reports and suggestions, super fun! I think a web build of my game felt unattainable for me for a lot of different reasons, and was maybe one of the main reasons to use an off-the-shelf engine, but wow, the mighty wasm really just made that all happen.

Huge shoutouts to the folks working on Empscripten and SDL2/3 who make all of that stuff work!!!

Shortly after, the layout and resolution changed to be more portrait-mode-focused, a touch-based marking menu was added (sorely needed this in the original), and before I knew it I was building a simple python flask app to run a redis-backed leaderboard!

The best part about this project is that it paved the path forward to putting Chronicles proper on the web as well! Not long after shelving puzzle sweeper, I got the main game running and I've been able to use that to run some small friends playtests and is perfect for demos.

Setting it Aside

I had a lot of personal doubt with the project that I struggled with throughout. Regardless of attribution, or filling a specific unmet niche for platform and playability, I still felt pretty weird about pushing out “the mobile clone” of a currently-popular thing.

It was still very much inside the launch window of that game's popularity and receiving updates, so regardless of my intent, it felt wrong to potentially capture any of that energy.

In the end, the thing the port really needed was new art, new characters, and a bunch more UI work. There are graphical tells on the monsters that give information about how the board works and so not having those felt like there wasn't much point in releasing wider, particularly to anybody not familiar with v1.

So I set the game aside and took a break, going on to spend more of the year focused on the main game. It wasn't until early December that I felt inspired to pick it back up and put in the last 3-4 days necessary to polish it up for launch. By that point, it had been nearly a year and so I felt a lot more comfortable with saying “this is a remake of this other great game, here's what I changed and why, I hope you enjoy!”

Launching on Itch

This was an interesting experience for sure! The game spread fairly quickly (or as fast as I've seen from any of my stuff) on Bluesky and Mastodon. It was very fun to surprise old testers of the original version from earlier in the year 😄

24 hours later, the game had reached 1000 Browser Plays! It was exhilarating to watch people get into it, both old dragonsweeper fans and new people who hadn't played the original. I think my favorite comment was someone saying “Oh it's just a remake of dragonsweeper, even better!” as though I needed anything clearer to silence the aforementioned impostor concerns.

I was just so happy to see people understand the vision for it and enjoy it. Laura Michet blogged about playing it through her holiday travel day and just being able to provide that specific thing to someone really filled my heart with joy.

Itch discoverability of course seems very opaque and strange, but it was wild to see the game bubble around the various New & Popular lists for a few days.

About 5 days in, the game started appearing under the “Fresh Games” section of the main site and that is when visits from itch.io really started to surpass the others and impressions hit all-time highs. At some point there wasn't much of anything I could about it anymore, it was out of my hands, and I could just refresh the analytics page like watching an ant farm to see what happens.

3 weeks in, the game still sees over 100 daily browser plays (5000 and counting!) and that's just incredible to me. Recently a community of people from Brazil have gotten extremely into it and made the time leaderboards extremely competitive!

I've received so many kind and wonderful comments and messages from people who enjoy to game or inflicted their families with it, it has been such a wonderful, joyous experience and I'm so happy to have pushed through and gotten the work out there.

What's To Come

I've returned to work on Chronicles, so look forward to new updates there, but I am keeping an eye on Puzzle Sweeper! I have a lot of thoughts about what an update to that game might look like, maybe if it hits some arbitrarily exciting browser plays total I might start to tease something 👀

Thanks for Reading!

I'm kicking myself thinking of a handful of other things I wanted to cover but I think this is long enough for now. Thank you all so much for your support and I hope you have a wonderful day!~

Wishlist Chronicles IV: Ebonheim! 🌐   🙋‍  

I read an extremely excellent blog post by the extremely exceptional Dr Holly Nielsen about her work in the upcoming Amberspire and I do just keep thinking about it a lot.

In the piece, she describes a setting in the game of a moon-sized ancient mausoleum with a contemporary city built on the surface. Holly suggests that the creators and construction of the superstructure are so far removed from the memory and knowledge of the people currently living on it that it's effectively a natural occurrence; fitting into the lives and culture of the city's people the way an ocean or mountain did in early Earth civilizations.

This is of course fascinating and you should just go read the whole post! The part that has me thinking a lot is her talking about this being an example of tension between macro and micro histories. I often think of micro history directly informing macro history and I was surprised to think about this as the tension between two different scales of history that aren't really temporally correlated. In this case, the history responsible for the existence of the superstructure are vastly disconnected from the lives of the inhabitants, which allows it to exist as this sort of effectively-natural environmental fixture.

It's got me all sorts of in my head about a lot of opinions I've had for a while while working on the world and lore for Chronicles. I really want to get some of those thoughts down on paper in the context of this excellent point and so this post is about the hierarchical causation graph of the micro-histories that ultimately directly result in macro-history events, the two scales being tightly-coupled.

The Timeline

I think a lot of worldbuilding and lore is really preoccupied with the timeline. There's the big list of years where major events happened and you can run the history back to creation or there's a map where the regions are painted different colors depending on the year. I'm not a historian but I did play a lot of Crusader Kings II and I read a lot of Wikipedia so I'm qualified to parrot what a lot of really brilliant people have said which is that maps aren't people.

The Graph

The human body is an incomprehensibly complex biosphere of independent organisms going about their lives serving their functions and reacting to their environments. White blood cells and gut flora and toe fungus are all living, breathing, dying in various pathways and recesses as they always have. We attribute the words and movements of the macro-organism human to a single intelligent actor but these are still the result of countless micro-interactions by a vast interworking ecosystem that happens to produce an understandable output.

So is it with human macro-history. We learn and/or memorize the big beats of wars, regimes, notable individuals, and reforms. We recite timelines or we coalesce ranges of years into easily-digestible “attitudes” that we then prescribe to entire populaces. It's easy, I think, when working from a timeline of major events, to draw conclusions, or find little stories to tell. Once you've smoothed over all the trite detail into a list of memorable highlights, we can naturally play with the blocks.

But once you begin to drill down into the how's and why's of a macro-scale event, the ground opens up under you. It's an infinitely-recursive graph of causations and relations with vanishingly smaller events precipitating, extinguishing, or contributing to each other. The smaller events have their own universe of who's and how's beneath them and so it goes all the way down to the atomic level. It's the whole chaos theory butterfly flapping its wings thing but with the understanding that there are so, so many butterflies, and they're all just doing their own little butterfly things.

Now obviously, being human, we can't just keep the whole graph in our heads, it's unknowable and too big. We have to categorize and generalize and coalesce and organize. It's important to remember, however, that the graph still exists. When learning new facts and getting new little blocks to inform our personal understanding of the world, it's easy to take the simplified view and draw simplified conclusions. This I believe is where we so often run into trouble.

One of the most problematic results of this in my experience is inaccurate assumptions of power. The extreme version of this would be conspiracy theories where the timeline clearly points to evidence of an illuminati-like guiding hand running everything. The simpler and more common version is assuming that all evil actors know what they're doing, have full control over the system, and will invariably succeed in their evil plans.

But can one human, or a thousand humans in perfect unison, directly affect macro-history? It would be a powerful feat, and has rarely or perhaps never happened. Under and astride that human are more humans, with their own wants and desires, and within those humans are biospheres of microorganisms thwarting or boosting them at random. Against that graph of actors is an array of resistant and oppositional graphs that all conflict inward and out.

When an event happens, one big enough to be remembered, and placed on the timeline, and recited for school tests, it is the final comprehensible output of an incomprehensible system that could have gone a whole different way with just a few tweaks circumstanced.

It is, I think, an error, to predict future macro-events from the surface-reading of the previous macro-events.

Uuuh, Videogames?

Oh, right. Sorry. What I'm spattering on about and trying to tug at is two things:

Macro-history is a direct result of vast numbers of micro-histories

There are no gods. There is no divine plan. The King is an idiot. The interconnected graph of individual actors making decisions against their own judgement systems versus an unchangeable state of the universe eventually produces comprehensible events we can remember and grapple with.

Macro-history is effectively uncontrollable

The graph of daily life is so intricate that it produces effectively random results. Like the building of the moon-sized mausoleum, macro events are much like naturally occurring environmental events. The further removed the living individuals are from the history that produced that event, the more like a mountain, or ocean, it will seem. It becomes another state of the world to content with and try to survive around.

The macro is meaningless without the micro

It's very common in fantasy to treat the world like a timeline, to orchestrate the list of events into a convenient and narratively-satisfying plot. But who were the people? What part of the graph did they affect?

It's discordant to our brains to hear a history when there's no concept of what almost happened instead, or what could have happened. That's because the event written into the textbook is just the final snapshot of an immense system that was vying for something different.

The Wikipedia hole is something I love to fall into. You can always go deeper and deeper into the graph and try to tussle out a better feeling of the why or how of what you started with.

This is because real history didn't start with the timeline working backward to fill in details.

All of this considerable talking is to say that I hope that any world I ultimately end up creating feels like a place where things happened, small things, in vast number. I hope I focus very little on the big chapter headers of the world's history.

They are just mountains and oceans; fixtures of the world you inhabit and traverse.

Wishlist Chronicles IV: Ebonheim! 🌐   🙋‍  

I was possessed to jump through hoops for a couple of days and get my Steam page up and running. The consensus agreement I've seen from developers is to have the page up and going for a long while before release so as to have more time to accrue wishlists, the magical currency that the steam algorithm consumes like a voracious tortoise.

If you, RSS friend, would like to feed the creature, you may add the following page to your Steam Wishlist:

New Website Who Dis

I have also given a small facelift to the game's website; adding a fancy embedded widget for the above store page as well as adding “Marketing Assets.”

Don't worry, you can still track the Line of Code count.

Community Management

I have also launched a Discord server for people to mute and never talk in. If you're in need of a new place to do that, you can join here. I would like to use this for corralling playtesters but I'll still be contacting that list via email and joining discord is optional.

So We're Almost Done Right?

Well, no, we're really going to have a long long time to accrue wishlists. But! The tutorial section of the upcoming playtest is pretty much done and I had some friends & family tests that were incredibly enlightening. I think the project is in a really great spot right now!

I don't think it will be very useful to playtest this tutorial because it's still quite linear and guided and most of what I would hope to get from playtesters is unique and creative solutions in very unguided open ended parts of the game. So we're back to the content mill to make something for that!!

I have a very good mental map of the next playtest and I'm getting going on it this week. As long as I don't completely burn out and die, I may have something to send to testers around Halloween 🎃

Thank You!

If you're a long-time reader I want you to know that you, personally, mean a lot to me and I think that you're neat in a strictly parasocial way.

Wishlist Chronicles IV: Ebonheim! 🌐   🙋‍  

It's June 28th 27th which means that three years ago todaytomorrow I decided to try to #gamedev again and made my first commit to a new repo for a new engine attempting (for the fourth time) to make a game with the title “Chronicles IV: Ebonheim“

Last Year I talked about the history of the project and showed off some never-before-seen footage from past attempts (Chronicles IV: 1-3?). And earlier this month I shook the cobwebs off after a long break and gave an update on how the project is going and how I'm feeling.

Today hasn't hit me as hard as last year did. Looking at the calendar and seeing that the project was already 2 years old reminded me of some past forever projects I had worked on and made me think of a lot of my fellow indies pouring a decade of nights and weekends into their work. I was generally very against this game being a long-term project and wanted to have a good idea of goals and timelines so that I could feel like it has an endpoint.

And to an extent, that is still true, but the first half of this year reminded me that I'm not really in full control over the timeline of this project and its only hope of success lies in accepting and being at peace with this fact. As I wrote in my last post, coming back and just working on cool shit has been the most fun the game has been for a while and that has been a huge boon both for the project and my feelings about it.

What's Next

I am still, for whatever it's worth, working on the next playable milestone. I'm so incredibly pleased with the work I've gotten done this month on both game and tool features. The scope and breadth of the demo is coming into focus and a lot of really great progress has been made as I continue to chisel it out of a block of marble.

The game's nearly unrecognizable from a feature-set perspective from the last release and that's another reason it being a year later doesn't hit me all that negatively. I took a break for 6 months, have better mental health, and the game is really just so cool now.

The Web

One pretty exciting little detour is that I have managed to leverage my work from puzzle sweeper to get my engine fully playable on the web using Emscripten.

It's a little awkward because it plays perfectly and loads instantly and is feature complete so it begs the question of “uuuuh I was planning on selling this on Steam?” I'm a little uncomfortable about someone just right-clicking the 3 files from itch and creating chronicles.com but I don't honestly know how worried to be.

At the very least, everyone can expect playtests to be playable in-browser and for release demos to as well. It's such an amazing boon for letting people just drop in and try it with zero friction I think it's going to help a ton for getting people to give it a shot!

Thank You

This game has been such a great warm blanket for me these past three years that I just always enjoy coming back to and hacking away at. I'm so proud of what I've accomplished so far and I am really just so crateful for all of the support and interest from everyone I've interacted with online.

Look forward to a new playtest coming hopefully before the next one of these birthday posts!

Wishlist Chronicles IV: Ebonheim! 🌐   🙋‍  

It's been quiet here! In the spirit of the last post, I figured I would drop in and write down the current status of the game.

Where have you been?

As with the year prior, I burned myself out pretty hard from spring through summer right into autumn and was feeling very tired by the end of the year. My stated goal of having a new playtest milestone shipped before the end of the year became less and less likely as that date approached and I started to feel disillusioned with any potential timeframe I could set. I was feeling discouraged by this and suddenly all of the pending tasks felt arduous and tedious and I worked on it less and less.

By January, I had fully settled into a now-traditional winter gamedev break. In November of 2023 I got into Armored Core 7 and then Dwarf Fortress and allowed myself to take some time away from my game project and focus on other things. This then coincided with a lot of life troubles that ate up most of my bandwidth and so I didn't end up picking the game back up until the following April.

This year was very similar! I played a lot of the excellent Caves of Qud and then had a lot of life troubles that needed my focus. The political climate in the United States also ultimately resulted in my being completely absent from all social media for about 4 months, which I highly recommend if you get the chance.

Side Project: Dungeon Puzzle Sweeper

In mid-January I became obsessed with the very-good Dragonsweeper which ate up a lot of work hours. I really wanted a version I could easily play on mobile and I wanted high scores and time leaderboards, so I decided to make one!

I cloned the v1 of the game fairly faithfully in the chronicles EGA engine and got it running in web browsers using emscripten and wasm. I implemented a wave-form-collapse constraint propagation algorithm for generating the board which was a fairly huge improvement over the original game's method.

I kept updating the game for about a month and had quite a few people on Mastodon and Bluesky playing it and posting times! It was great fun and a nice distraction from my larger game project. I felt on-the-fence about publishing a game that just clones the 1.0 of Dragonsweeper and wasn't sure what to do. I also needed to create new art to really make the version complete and these two things together led me to drag my feet on the project.

Around this time, life troubles and political climate swept into full force and I retreated more fully into silence.

You can play my Dragonsweeper clone here on my website if you'd like! It's optimized for mobile, doesnt eat your battery, and you can compete with your friends for your best time! I dont know what, if anything, will ever come with this cool little thing.

Returning to Chronicles

On April 22, I returned to online and over the next few weeks started trying to make a plan for continuing development. There has been a lot of work that I would love to make some technical write-ups for but mostly I've been posting my progress as usual on Mastodon.

A lot of great new progress has been since then as I've built up more and more momentum:

  1. Fixed-Point: I've needed a way to model non-integers in the game for a few things such that the game is still purely deterministic and not prone to floating point error so this was the first thing I did. I used this to fix some viewport/camera stuttering issues the game always had!
  2. Smoke Wall: One of the nearly 30 new abilities I built using my asset editors in April.
  3. Tile Target Animation Cascasding: An architecture change that lets me sync up ability actions better.
  4. Tile Schema Elemental Interactions: This has been a big thorn in my side since last year. You need to be able to use water on torches to put them out and that works now along with a ton of other cool things this enables.
  5. New Enemy Art
  6. Single-Tile-Wide Wall Lighting Fix: Another forever bug that I was ignoring for a long time and finally have a good fix for
  7. New Tree Art
  8. Fixing Shadowcasting: This is maybe top of the list for a more detailed write-up. My lighting algorithm ahs had edge cases problems forever and I finally sacrificed a weekend to building an interactive editor and understanding the underlying math to finally fix it for good.

On the Future

When it comes to having a timeframe in mind for a next milestone release, it's fairly far from my thoughts at this point.

As I've settled back into the game I'm discovering that my mental model for how close I was to having something ready to hand off was completely delusional. Yes I had enough that I could comment out some unfinished things and throw some maps together like I did with the first playtest, but my original desire for what I wanted the next demo to be is still a ways off. I think I was really fooling myself about how much work was left in the “just make a dungeon” to-do item.

Being completely offline for such a long time has also really helped me to now see how much I had slid into some really self-destructive behavior. When I started the game, I had no timeframe in mind and it was just something to fiddle and tweak in my spare time. I mostly enjoyed having technical accomplishments to write up here for other developers to hopefully get something out of.

As time went on, however, I sank deeper into a hustle mindset for creating online content for showing the game off. I always needed to make some new screenshot or gif or get it out there into people's feeds and hashtags. And there's nothing necessarily wrong with this, but I also started to put more and more weight on the release schedule I was putting together so that I could get it out and selling. I think these are things that are important to do for selling your video game but it was also really turning the project into a very negative thing in my life.

Now coming back and seeing the broad broad broad field of titles being produced by countless people, the idea of finding any sort of audience for if Chronicles ever actually ships has started to feel futile.

But I think the thing I've noticed is that being away as long as I have has cured me somewhat of these realities as stressors.

I'm really just back to fixing engine issues, creating new architecture, and getting excited all over again about new enemies, new abilities, new content, new features.

It was very eye-opening to be fully back into the development saddle and then realize that I had at no point even thought about setting a new release date for myself.

I absolutely will be sending copies of the next milestone out when it is ready! I can't wait for everyone to see what I've been doing and let me know what they think. I just need to let the game itself tell me how much is left before it's ready 😊

Thank you!

If you read all of this, then you've probably been reading my stuff for a while and I really appreciate you! Stay safe out there and take care of yourselves!

Wishlist Chronicles IV: Ebonheim! 🌐   🙋‍  

It's been a little bit since I've sat down and blogged and, while I have a few long-form write-ups in mind, I did want to drop in and give a short status of the project and how things are going.

Some Bookkeeping

I'm on BlueSky! I was on BlueSky before and continue to be. I harbor a deep distrust and series of smug sideways glances toward the platform and will continue to primarily be present on Mastodon but if you are a skeeter or skeet-adjacent, you can find my major updates and gifs on the blue butterfly.

I have a new email address through the extremely excellent Fastmail! This affects 0.1% of you but play-testers or anyone who has reached out in the past will now receive correspondence from bri@brianna.town. If you're the clever sort, you might even add it to your email contact list so that it doesn't get spam-folder'd.

The Milestone

If you're weird enough to have been closely following updates this year, my original plan to ship the next playtest milestone on Halloween like last year was severely hampered by not getting to do much of any development until late spring.

In the last 6 months I've accomplished a ton: contiguous world map, lighting, line of sight, inventory, equipment, the core game loop, and more! The only person holding onto the due date for the next milestone is me but I did definitely want to get it out to people before the end of the year. And it may still happen! (Dec.3, Narrator's voice: “It won't.”)

Right now I'm entering the big content grind where all the features need to be used to create abilities, items, enemies, and maps to house all the features I want to show off in the milestone. One of those not-yet-written write-ups is talking about the project-management of designing encounters for an RPG 😪

While the last playtest was strictly testing the combat mechanics, I want this one to more or less feel like the real final game in terms of progression and loop, so there's a ton left to do.

Still need to create some new music and sound effects too!

Want to Help Playtest?

If you haven't reached out about testing and wish to be contacted when the milestone is complete, please reach out through any of the various channels! PC, Mac, and Linux players are welcome! The playtest will have the ability to automatically upload replays of your playthrough (which you can opt out of) and will include an optional set of feedback prompts to ponder as you play.

Last year's playtest was such an overwhelming success and I can't wait to get back with folks again, hopefully this year!

Wishlist Chronicles IV: Ebonheim! 🌐   🙋‍