Live Dev Stream! -- Alchementalist (Viewer input encouraged!)
Come and join me in a coding sesh! I'm keen to have some viewer input on the game, so drop in and give me your suggestions or requests about anything that you see, or just AMA.
I'll be focusing on the crafting, alongside spell boosts and new wands. Maybe some work on the enemies and some bug fixes, who knows!
Alchementalog #2: A Song of Stats and Boosts (Part 1)
Despite the fact I’ve been doing pretty regular mini updates on Twitter, Reddit and Youtube, I haven’t really written a proper devlog entry for Alchementalist yet (I mean, I’ve kind of done one previously, but that’s it!) So let’s rectify that!
In this devlog, I want to talk about the work that’s gone into the stats and boosts system. It’s been quite a journey so far and the magic system I envisioned for Alchementalist covers a fairly extensive amount of unknown ground for me, so there’s been a lot of false starts and dead ends I’ve run into. But I think I’ve finally managed to come up with a system that works well and has the flexibility to contain the many different effects I want to be able to implement with the boosts (at least I haven’t run into anything that breaks it yet).
I’ll begin with an overview of the stats system. I wanted both the player and the spells to have separate stats, with the spell stats obviously changing depending on what spell you had selected. Spells can be crafted and dropped into your spell slots, so everything to do with spells had to be dynamically changeable on the fly (player stats also had to be dynamic, but we’ll cover that when we get to spell boosts).
Spell stats include things like the element associated with the spell, the strength, range, cooldown, crit chance, damage radius, etc. Generally the stats you’d imagine. Player stats included things like experience, level, element type level (so, a separate simple level for Fire, Water, Wind and Earth), hp, move speed, etc. These are all pretty basic concepts for an RPG-ish roguelite thingy. However, I haven’t actually worked with a system like this before. It’s my first dive into RPG stats.
To begin with, I had the simplest implementation imaginable. An array I accessed with enums storing the value of the stats:
This was fine while I was simply building up the prototype, it let me access what I needed when I needed it and so on. So after building that simple system, I moved on to other things like level generation (part of the joy of being an independent developer is being able to work on things whenever you feel like it and swap between tasks at random, keeping things interesting). During this time I also built the elemental effects system for the tiles, which I’ll probably cover in a future devlog.
Once I’d finished getting the barebones skeleton of a game up and running, I desperately needed to do some refactoring as things were really starting to crumble under the weight of all the half-assed systems I was piling on top of each other. So it was time to dive back into the stats system code and start getting things running so I could start testing out spell boosts and experimenting with how they would work within the game.
So what’s the problem with my original implementation of stats? Any experienced programmer should be able to spot it. How in the world do I keep track of the changing nature of stats. What happens if I want to implement a +5 to player HP on one boost and a 25% increase to player HP on another boost? How do those two increases interact? How do I keep track of what the base stat was? What happens if I need to remove one of those boosts? My simple little implementation was going to need a big overhaul in order to deal with these problems.
The first thing I always do when I need to implement a system I haven’t done before is to do some research! A lot of problems a programmer will run into have been solved before and there’s no point reinventing the wheel if you don’t need to (not to mention someone else’s wheel might be rounder than the one you are imagining). After a deep dive through google, I had a few different examples of how to handle RPG stats and so I set to work implementing my second version of stats.
To get down to some of the nitty-gritty details, each stat itself is a struct. These structs have a base value, a max value (if applicable), a variable keeping track of if anything has changed, a variable holding the final_value (the base_value + any modifiers) and an array that will hold any modifiers (as well as a few other “bookkeeping” variables). There’s also a bunch of functions in there to deal with adding and subtracting modifiers, as well as calculating the final_value of the stat and things like that.
A portion of code from the Stat constructor function. This creates the struct for a single stat.
Whenever I want to modify the stat, I called the AddModifier() function, which creates another struct containing the details for the specific mod. So for example, if I want to add +5 to hp, the modifier struct created by the AddModifier() function will look something like this:
{ value = 5; type = e_stat_mod_type.FLAT; source = spell_boost_id; duration = -1; order = e_stat_mod_type.FLAT; }
The value and type combine to tell the computer how this mod interacts with the stat. The source is the id of whatever thing added the mod (this is useful to track, as it both allows you to display to the user the sources of all the mods if you want, and also allows you to do things like remove the mod if the source is no longer valid, etc). The duration tells the computer how long lived the mod is (-1 is “forever” in this context), so I can implement time-limited buffs/debuffs. And finally the order defaults to the type (as in this case), but can be changed. This just lets me order the mod entries in the array according to whatever scheme I want, meaning I can optimise how the array is read.
This modifier struct gets stored in the array of modifiers for the stat. Whenever this array gets changed, I set the variable keeping track of whether or not the stat has changed (is_dirty) to true. Then whenever I call the function to output the “real” value of the stat, it checks is_dirty. If it’s true (as in, the stat has been modified since I last called the “output final value” function), it redoes the calculation, which involves looping through the array of modifiers and applying the modifiers in the desired order, finally updating the final_value to the appropriate value and outputting it. If the stat has not been changed, it simply outputs the final_value straight up, cutting down on needless processing.
The actual implementation is slightly more complex than this, but that’s the general gist of it. And it works great. I can keep track of everything, add or remove modifiers as needed and data only gets processed and updated as needed.
I have a stats constructor that I can call to build the stats structs for whatever entity I wish and I use the same stats for both spells, players and enemies. This is simply because it makes it a little easier to generalise the system and the few stats that are unused in the different cases don’t really add much overhead to memory at all. It just makes it easier to deal with (there’s also a more pertinent reason when it comes to spell-boosts, but we’ll get to that).
The Stats constructor builds the struct for an entity containing all the stats I might want to access/tweak.
In the case of spells, there’s also some additional information I need to store, like the sprite, the icon and various functions for different spell “events” (things like OnLaunch, OnStep, OnHit, etc). So the spells themselves are a struct that holds those variables and functions, alongside a stat variable which holds the struct containing all the stats (it’s structs all the way down). I call the spell functions at the appropriate times in-game, so when the spell is cast, OnLaunch() gets called for it. When it’s traveling OnStep() gets called. This lets me do very specific things with each spell (such as creating a burst of damage around the player when the spell is cast, or stuff like that) while maintaining a generalised system where each spell functions in the same way from the “outside”.
Now let’s say I want to add a new spell to the player. Well, I have a global array containing all the different spell structs in the game. I first create a copy of whatever spell struct I’m interested in adding and then I store that copy in the spells array that each entity has. The reason for the copy is that in the case I want to edit the spells data, I don’t want to be editing the original “base” spell.
So that’s the stats done, I feel pretty happy with it and it’s basically as extensible as I want it to be. If I want to add new stats, I can simply change the stat constructor and it gets reflected throughout every entity. Cool, cool, cool.
But what about spell-boosts? These were (are) a lot more complicated for me to implement. Part of the problem is the general fuzziness with which I viewed them. Before I started seriously working on them, I just had a general outline of what I wanted them to be able to do. Things like change stats, maybe create entities of some sort, alter elemental effects on terrain, etc. Not having a clear idea of the functionality of something you are trying to make always makes a good implementation much harder to achieve (some might say impossible). So the first thing I would need to do is start drilling down into the actualities of what boosts can do.
But this devlog is getting a little long, so I’ll save that for part 2!
Hope you enjoyed reading this little look into the process of creating Alchementalist. Stay tuned for the exciting conclusion of how I implemented spell-boosts into the game!
I’ve been doing a lot of work recently on enemies in Alchementalist. I want to get the game into a state where I can really test different mechanics out and see how the emergent gameplay works, and that means populating the world with a bunch of bad dudes intent on making your life as a player difficult.
The most recent one I’ve added is tentatively titled “Nightstalker”. They are void based creatures (which means they’re all dark and phantom-ey) and they have a teleport attack. Now whenever people talk about making their games, I always want them to drill down into the details of the code so I can learn actual techniques from them, but sadly, I’m going to disappoint even myself and not do that here, rather I’m going to talk about how trying to tweak some very minor graphical decisions led to more emergent depth within the gameplay of Alchementalist.
Firstly, let’s come to grips with the Nightstalkers. The mechanics behind the Nightstalkers is thus: You walk into their visual range and they “see” you, turning to face you, you then have a grace period where they bide their time waiting to attack, then they teleport to a random area behind where you are facing and finally they launch an attack that has a relatively small range.
Now the problem I had is that I had a teleporting enemy, but the teleportation was very sudden and it was hard to predict when it would happen, making them feel kind of strange and not too good to fight against:
This would be ameliorated by having a “windup” animation (all the featured Nightstalker sprites are very WIP and some animations are missing entirely), but I still wanted something that would make the timing a little more clear to the player beyond just a windup, so I settled on having some sort of targeting indicator.
My first iteration was this:
I was pretty happy with this (and it’s pretty close to the current implementation, at least for now); it gives a clear indication of when the teleport will happen and gives the player directional information about where the threat is coming from. However, I wanted some feedback about the indicator that wasn’t just my brain (which can be exceptionally stupid sometimes), so I decided to post a twitter thread asking for input. You can read the thread here if you want: The Thread.
Some helpful folks (@ottergamesdev and @Eluem and @sevenports1 specifically) chimed in and helped make the indicator look cleaner, but one of the suggestions wasn’t about the indicator itself, instead it was to make the area the Nightstalkers were targeting stop updating a little bit before the actual indicator resolved. The reasoning being that if the player is moving, the Nightstalkers will always be aiming a few frames “in the past” before they teleport and therefore their attack is a little easier to dodge through movement.
Now, I did have something similar to this originally. When I first implemented it, the timer after they teleported, but before they attacked was longer. I shortened it dramatically because I didn’t like the way the Nightstalkers stood there for a little bit like idiots after teleporting before they would attack. The alternate method mentioned in the twitter thread is better than my method because the “delay” is invisible to the player. It looks like they are always targeting exactly where you are, but in reality, moments before they teleport, they stop updating their targeting positions invisibly.
I liked the idea, so I implemented it in. Then I noticed something interesting. By adding this invisible targeting delay, it introduced an entirely new mechanic. Originally, as long as you were moving fast enough and you weren’t running directly through the enemy, you could escape any attack they launch. I was relying on the player having to avoid other enemies and therefore being forced into a situation where the Nightstalkers hit would land. With this delayed implementation though, the decision that reflected whether you would get hit was both the direction you were facing and the direction you were moving combined, a much more active decision compared to simply moving away from them:
Let me explain. The Nightstalkers teleport behind you. This means that if you are facing them, but running backwards away from them (as you almost definitely will be if you are trying to attack them), they teleport further ahead of you in the direction you are running because that’s the opposite of the direction you are facing, meaning you are essentially running into them after they teleport. If you are facing away from them while you are running away from them, they teleport behind you except this time, you are running away from them. This gives the player complete agency over whether they get hit or not. If you make a mistake and are attacking them when they teleport (meaning you are facing them), you will get hit. If not, you won’t get hit. Awesome. Here’s another example with the latest graphical iteration of the targeting indicator showing this more clearly:
You can see that as long as I’m facing away from the enemies and also running away from them, I will not get hit. However, if I’m facing them while running away from them, I’m guaranteed to get hit.
This mechanic was vaguely in the previous iterations, but because there was no targeting delay, it didn’t matter if you were running into them or away from them, it only mattered whether you were moving or not.
This is one of the many examples of why iterative design and getting feedback is a great thing. If I had of been happy with my original indicator and started working on something else, I would have missed a great chance of adding emergent depth. By spending a little more time and asking around, I stumbled into a perfect opportunity to add a hidden mechanic to the game. There will now be a noticeable difference between a skilled player and someone who is new to the game when fighting this enemy.
This might seem like such a little thing to talk about for such a big blog post, but part of making a game that people love is finding ways to squeeze all the sweet pulpy juice out of every little moment and giving them the opportunity to showcase their skill, even if it’s just to themselves. A player who is good enough can still essentially dodge every attack this enemy throws (as could be done before, simply by running), on the other hand being able to do that in the middle of a chaotic fight with other enemies and mechanical checks coming their way is very hard. But it’s not impossible, and that’s the rub.
Nightstalkers as they are in the game now.
Introducing Alchementalist to Steam
Hey folks, I've just pushed the Alchementalist steam page live! It's always exciting doing that for a new game! This announcement is a brief run-down of my current plans for the game, alongside a few extra links for you to follow if you like the look of it!
So what is Alchementalist?
Alchementalist is a spell-crafting roguelike dungeon crawler that allows you to manipulate the elements to create ever more crazy environmental effects! Fight enemies, mine ore, craft new spells, and try to work your way ever deeper into the mines of the Ember-mages in your quest to find the Ember-Source.
Features
Spell Boosts
The spell boosts crafting system allows you to alter the properties of your spells in a myriad of ways, as well as crafting entirely new spells!
Elemental Terrain Effects
The elemental terrain system allows you to craft spells that alter the very terrain itself! Combine terrain elements for even more crazy effects (for instance, combining wind + fire terrain elements yields a storm)!
Dynamic Enemies
The enemies in Alchementalist use the exact same spell boosts system as you do, which allows them to craft their own unique attacks!
Ember-Mage Mines
The Ember-Mage mines are part procedurally generated, part hand-crafted, in a combination of the best of both worlds. Each run is unique, but not chaotic, allowing you to develop strategies and learn to make the game work for you!
My goal is to make a fun, chaotically emergent series of systems that interweave with each other and lead to awesome gameplay moments for you! The game is still very early in development, so make sure to wishlist and follow to keep up with all the new updates as the game gets closer and closer to completion. You can even participate in the creation of the game by posting on the Alchementalist subreddit or Twitter and letting me know what you think or even suggest things for the game!
Thanks for reading this brief announcement and I hope you have a good day!