Work was busy, and the particular feature work I'm doing right now is really not that enjoyable to look into, but necessary for the project. Trying to motivate myself to finish this, so I can look at something else, but there's a ways to go with it.
I did a little more coding on Wiz, moving things around and attempting to clean things up. Still lots of mess to still go with this, but starting to see the other side of it. The intermediate work is kind of unenjoyable to do, but trying to keep working through this. Lots of stuff that probably needs to get organized better, and it's painful to look at. Trying to split things out into the smaller subsystems, and fix up all the dependencies between the different subsystems, so the whole thing can compile again. Even if it means a mess in the meantime, hoping I can close this out at some point.
Again, it would likely be way easier to do this cleanup work if it was tired to a direct feature or something, but unfortunately, I put off cleaning up the technical debt for too long. Making it hard to add features without growing the mess, and hard to adapt much of what was there without a refactor in the first place. But this is stuff I've said already at this point.
I'm kind of discouraged how slow this is going, but considering I maybe only spent a few hours total, spread out across days, it's understandable why this is a slow and tedious process. Still, if I can finish up this initial pass at splitting everything up in some form, then I can worry untangling things. It might be easier at that point, because it will be possible to divide-and-conquer the pieces to tidy up, without impacting the others.
Also, on Sunday I got sick. Originally I just thought my apartment was stuffy, or maybe I was dehydrated or something, because it was really warm out. But I drank plenty more liquids, and the symptoms persisted overnight and during the rain. I don't have a thermometer, but it's 17 C at night and I didn't really feel this at all. During the daytime today, I actually thought I was better, but tonight the fever-like aspects returned. I've been isolating at home and have the windows open and fan on. I currently only have 1 of 2 vaccination shots, so there's always a potential risk.
I had originally planned to have a stay-at-home vacation at the end of this week, but I'll most likely need to cancel, so I don't burn my vacation days as sick days. Unless I get very lucky and this thing resolves itself by the morning or something. I have a feeling I'll need to get a test and self-isolate at home more, which is not fun.
Wishing that this blows over quickly and crossing fingers that it isn't what I think it is. Hope to talk more next week.
Howdy. Another week, another update!
Since last week, I continued some more refactoring on Wiz when I got some free moments. I kept working on splitting the compiler code into a few smaller parts. The division right now is a bit arbitrary, but it's good to start somewhere.
A lot of functions that used to be instance methods were rewritten to be free functions instead. One nice advantage of this, is free functions can't act on private state (without gross C++ features like the "friend" keyword). As a result, more fields become public, and data structures are a reworked to be bit more transparent.
Another nice property of using free functions, is that it's possible to move these functions around between source files without problem. Also, for places where the information hiding is useful, or the implementation details don't need sharing, some things that were previously private data + functions within
Compilercould be put into a file-local anonymous namespace instead.
For now, some things were rewritten to take a common
CompileContext, containing various smaller systems and state across the course of compilation. Eventually the big mess of data members can be organized better into smaller logical parts, and some things that take a full-blown
CompileContextcould take a (possibly const) reference to a specific subsystem they need. This would make dependencies and their usage clearer to tell from the function signature. Some of the reworked functions already do this, but still working out the details for others.
I'm currently working on just moving the code, with minimal changes inside the actual function body. But I intend to clean things up more when things are divided further.
As an example of something I want to clean up better,
reduceExpressionis a function that reduces an expression tree into a smaller form. Given a abstract syntax tree for an expression with no extra information, it does semantic analysis and produces a partially-folded expression tree with type-annotation on the nodes. It can also take a previously-reduced tree and attempt to reduce it further. For example, expressions with references to constant symbols that can't be fully resolved during the initial compile, but can be figured out during the final code generation.
Anyway, turns out this function is like 1000+ lines of different cases + logic, basically it sorta outgrew itself and code just kept getting added there. This could easily be split up into a bunch of smaller functions. Splitting up the big mess has made it easier to spot the clutter within.
There's also the issue of naming things better across this codebase. For now I just sort of called things the first name that came to mind, but there's room to rename and make it clearer. Ideally naming should be short, concise, and clear, and consistent where possible.
Trying to not fall into the trap of nitpicking over minor things forever. Better ideas might come up when more important changes are made anyways. And there's a point where it's "good enough". I just want to get it far enough that I hopefully won't feel that I've coded myself into a corner anymore. It still will probably not be code I want to look at or work on every day. But having things more organized still goes a long way.
Anyway, more work to do. Hopefully I can keep the motivation to continue this. I'd really like to finish this cleanup so that it's easier to add testing, do bugfixes, add new features, etc. like I've been talking about. If I keep working a little bit at it every couple nights or so, I can eventually get this into a more maintainable state, but it's a matter of having the energy and attention for it.
In other news, the MSX2 computer I ordered way back in March finally arrived. The model I bought was the Panasonic FS-A1. The box art on this is... pretty incredible hahah. The orange-on-black look of the console system is very cool too.
Here's a brief video I posted on Twitter of it running!
Unfortunately, the phone didn't pick up the audio from my TV (unless you crank up your volume), but the flash cart also supports the SCC expansion audio chip that Konami games for the MSX used. Nemesis 2 has a solid soundtrack, and it sounds excellent coming out of a real console hooked up to an old CRT.
It doesn't have all the bells and whistles of some of the last generation MSX2 systems, like the MSX2+ and Turbo R, but I can live with it. This console was in great condition and in my price range. Meanwhile the later revisions are exceedingly more rare and expensive for only a handful more titles, and only slightly better specs. I think the middle-of-the road option is good enough since it supports all the MSX1 games, and most MSX2 games work ok except for a few exclusive releases for the later models.
The seller also had the option to add some kind of RGB mod, but I don't have equipment to handle that at the moment. And from reading online it sounds like I maybe dodged a bullet there. They didn't appear to have great feedback online for this particular thing.
Meanwhile, they took a picture of the recap they did before sending, and thankfully the work they performed looked okay, from observations as a layperson. No damaged traces or anything like that which I could notice, so hopefully all good on that front. Always a bit risky to get unknown eBay sellers to do work on a system, but thankful that it all looked good. Especially since I found out this information by searching the seller name after the fact.
In any case, it works great when plugged into my old C64 monitor over composite. I could also probably plug it into my RetroTink 2x and use that for capture. Even if the signal isn't going to be super crisp, it'll probably look good enough. I could possibly find a reputable modder to install something down the road if it's possible to have a cleaner video output, but not in any hurry for this.
There's more encouragement to get back to MSX development, now that I have the ability to run and test stuff on the real thing. I can continue my port of Wandering Magic and see the results on an actual console, instead of just in an emulated environment. Or maybe tinker around and work on something else that seems fun to make, too.
That's all for this week. Catch you later!
Hey everyone. This week flew by fast. I did my last update two days late, so there's been less time than usual between my posts. I almost missed my post tonight, even with things back to normal + the usual notifications I have going for posting on Monday nights.
I got a little spark of motivation to resume work on Wiz, my high-level assembly language. I've been working with the private repo branch I recently re-made, so I can take my time to mess around with these changes and not block the public upstream.
I decided against the 'delete code and re-add' approach when it came to refactoring the project. This is because it would mean losing the ability to run the program against example source code until the refactor was completely finished. These examples are currently the closest thing I have to tests for the compiler. And because they're fully running programs, not only do I get to see if the compiler works, I get to look at the resulting program in an emulator to see the product of my work. So anyway, that's why I don't think that a clean slate fashion of rework would go very well, without putting a lot of old code back, which would inevitably probably end up rushing things back to the position they already were.
(Well, there are some functional test suites, but they aren't as interesting to run right now, since they mostly test the codegen pass. I eventually will rerun these though. And I also want to write seams to allow for some proper unit tests...)
Instead of the "destroy-and-rebuild", I decided that I would start by moving existing code into separate smaller subsystems: lifting things out of the compiler source and into their own file. For a good place to start, I moved all code related to scoping, name generation, and symbol resolution. Thankfully, all of the scope-related stuff has almost no dependency on the rest of the compiler, so it's an easy candidate to move. This is just moving things over mostly so far, but I did make some minor improvements. It is giving me a chance to re-read the various pieces and see things that could be done better.
Things still have a long way to go, but if I can have like 4-5ish smaller systems, rather than 1 giant intertangled mess, I'll feel better. For some reason, doing this sort of cleanup on a personal project seems like such a chore. I guess because it's an unpaid project, I'm the only maintainer, and there's limited appeal to work on a compiler in the first place. For me, I have to be in a specific mindset to want to do tools-related work. Also, I don't want to break the publicly-available upstream version of the code, since a few people are using it. With the project already "released" kind of, it feels more difficult to continue do new things to it, even though I'm in charge of its development.
With a compiler especially, people tend to expect minimal breaking changes to the language. and any change needs to be considered carefully so it's actually an improvement, not a step backwards. Anyway, this is why getting to this point has taken a few failed attempts at wanting to get around to fixing the project, months apart. Having a private dev branch has made things feel a little less risky at least. I also have less anxiety in general around making bad choices, since I can at least squish any bad decision before it becomes a part of the public release,
If I stick with this and finish on this, I would maybe like to take a crack at improving some of the data structures in the compiler, and improving some of the patterns for memory management. The data structure things would be mostly a learning exercise, but also to have better control over the performance characteristics and share the same data structure implementation code across platforms, rather than depending on STL vendors.
In the case of the memory management, using arenas would allow things to be packed closer in memory, making them more cache-friendly. It would also potentially also allow more stuff to use cheap non-owning pointers to each other, and potentially avoid cloning in some places that currently need to do this. Cloning was needed preserve the current model of unique pointers + immutability, but in some cases, non-owning sharing would be possible. Shared-ownership pointers were deemed too messy a model since I didn't like the unclear ownership situations it could create, and I didn't want to pay the cost of refcounting, nor risk the possibility of a circular references being formed. Arenas are nice because they're simple to reason about, efficient to allocate, and can even speed up destruction if I refactor things to ensure everything is trivially destructable, since I could just release entire blocks of things at once.
I'd also like to see if I could make the code for describing the various instruction sets entirely data-driven -- it's mostly there but there's a few things that could use some work. If this were done, potentially it would open the door up for Wiz to define platforms and their instructions directly within .wiz. This would let people use use Wiz to target any architecture that there are rulesets defined for, even custom virtual machines too, if desired. It would also lessen the time spent maintaining these platform bindings, since they wouldn't need to be baked into the compiler anymore. I'd probably bundle some bindings built-in but allow superseding them with newer versions.
I thought adding compile-time arguments to inline functions would also be cool. It's an idea I had since early on, but something sorely missing. Writing specialized code without going for the manually unrolled and edited copy-paste approach is appreciated. Since Wiz allows constant-folding of if statements, there's also the possibility for compile-time specialization based on the arguments passed. Some people have even hacked in their own preprocessor pass to wiz just have #define macros heh. I had originally held off doing this feature so that I could evaluate how to do things, but I think I have an idea of what I'd like to do.
It could also be neat to structure the tooling such that it could interact with the Language Server Protocol used by modern code editors such as Visual Studio Code, Atom, Sublime, etc. If such a service was made, potentially tool-guided autocomplete and refactoring would be doable. My compiler needs a bunch more work to support that though.
One thing at a time though, let's see if I can keep cleaning things up and maybe spark more motivation I've been missing for a while. See you next time!
I'm late for my usual weekly update. It was a long weekend (Victoria Day weekend in Canada), so this threw off the normal schedule a bit. The weather in Montreal also warmed up, which was pretty nice outside. Indoors the humidity made things a bit less pleasant, and I had to get out a fan.
I've been struggling to make much headway on anything programming-related outside of work in a little while. I'm not sure why, but I guess sometimes this happens. I was a bit tired with my current projects, so I decided to start on something a bit different.
I had the idea to write a music engine for my homebrew NES games. I wanted to support FamiTracker, since it's the most popular music tracking software for composing music for the NES.
Before going down this road, it's useful to evaluate what's already there. A few other music popular NES engines exist that support importing from FamiTracker, such as FamiTone (or the older, original version here), GGSound and Pently. I've used Famitone and GGSound a bit, but they lack some features for making richer audio tracks in some regards. Never had a chance to try Pently.
There's also another tool FamiStudio, which is a separate piano-roll style desktop music editor. It has FamiTracker import, and supports targeting directly for its own improved engine fork of FamiTone. But from the page's own description, it sounds a bit closed to outside contribution and it's a larger codebase, so I'm bit unsure about it for this reason.
Anyway, I looked at what was there but wanted to try writing my own thing. Hopefully something that has easy integration into my own projects, and has good support for some of the tracker effects that FT has available.
I also wanted the potential for supporting expansion chips, to approximate the sound capabilities in other game consoles, such as the MSX, PC Engine, or Game Boy. It wouldn't sound 100% the same, but it would give a way to test these things out at least.
(MSX has on-hardware stuff like Trilotracker, and Game Boy has on-hardware LSDJ, and Nanoloop. But these are more strictly for writing and listening to music when nothing else is happening. Not meant as much for gameplay when the CPU is needed for other tasks too. There's also Deflemask or XPMCK, which support a bunch of platforms but also don't really have drivers that work great for a game. GB also has Paragon5 Tracker, but it's ancient and clunky. So in light of all this, something like using FamiTracker to approximate ends up sounding like a good possible alternative.)
I've previously worked on a a couple attempts on different music engines, but these always relied on notation similar to MML (Music Macro Language), or byte-code interpreters that used command opcodes for notes+effects. In these cases, I was writing the engine, but didn't have easy integration to a usable music editor. They had sample data or text-based formats that they could convert, for the purposes of testing what sound engines were capable of, but nothing easy to actually make music with.
There was also Bleep, an unfinished piano-roll music maker I was working on that ran on the GB hardware directly. While this was neat, and I want to continue with that someday, it's less practical for game music making, and was more meant as a fun way to make songs on the go. For my current idea, I wanted something with easier integration with a desktop music editor that does chiptune music. Different goals.
Alright. So this time, I wanted to make a project that took things in the other direction -- rather than engine-first like usual, I decided to try doing an importer tool first, then a converter tool. This way, I could write a music player that can interpret the parts of FamiTracker song that I support so far. This would allow making music in FamiTracker from the beginning. I can incrementally add support for more things, while being able to compare the output from my engine vs the FamiTracker. I can also use my past sound engine work to fill in some of details later when I get to that point.
FamiTracker's normal file format is a binary and seems a bit annoying to handle. Not impossible but probably would take some extra time to get right. Thankfully, it also has a text-based file format that it can export that is (comparably) much easier to handle. Sadly, according to its own documentation, this export is not guaranteed to stay stable between versions... However, it turns out FamiTracker doesn't change all that often anymore since it lacks active maintenance for the official version (last release in 2015). I also find it unlikely that they would abruptly throw it away fully, since lots of external music engines + converter tools depend on the format working a certain way now. So yeah, text format it is!
The format documentation is included in the
.chmhelp file that comes included with FamiTracker's installation. I couldn't seem to find a direct online version of the text format specification on their wiki or website.
However, through a roundabout way (a github page that can link to .html files in github repos), I'm able to link to doc for those interested: https://htmlpreview.github.io/?https://github.com/HertzDevil/famitracker-all/blob/master/hlp/text_export.htm
This format is a simple enough: text-based format with line-based commands consisting of space-delimited tokens. But there's some slightly tricky business comes with how it handles strings, which need some escaping. Otherwise, not to much to say about the format itself. The commands of the format do stuff like define tracks, instruments, macros, etc, piece by piece, as each is read and interpreted. It's kind of unfortunate that it's a custom text format, rather than just using JSON or something, which would make it a bit easier to integrate without other tools needing to write a new parser. But what's there is still pretty nice. Parts of it can be more easily be human-read, and the music patterns themselves essentially look very similar to how they're written in the editor, so it's easier to inspect.
I originally wanted to write this tool in C++, but kinda regretting the decision to not just phone it in with a Python script or something instead. Writing anything that handles I/O and text handling with nice graceful error-handling always takes some work to get right. All in all, it's pretty much the equivalent of
split()with maybe a couple regexes, but I ended up settling on a simple character-by-character scanner instead since I could have finer control over the memory usage and more easily do input validation and errors with line info.
Aside from the text input stuff, I made decent progress on some data structures representing the in-memory representation of a FamiTracker document. That part was kinda fun to work out, going backwards from the description of the various commands in the export spec. I'm sure if I need I can read the FT source later too, but I wanted to "clean room" things a bit for now.
Anyway, I did manage to write most of a parser + a bunch of struct definitions for the FamiTracker's document structure, individual tracks, patterns/rows/columns, instrument definitions, macro sequence definitions, etc. Didn't quite get to the end, but close.
If I can manage to get this parser done, I can start selectively outputting parts of FamiTracker songs from this tool. Or potentially toss it out, treating it as an exercise only, and maybe think about doing it as a Python script after all heh. We'll see.
I ended up returning a little bit to development plans for Wiz, too.
I created a private Git branch of the source to allow me to try stuff. I like open development most of the time. However, for big changes, it can be annoying to make sure breakage doesn't happen at every step of the way, once people are able to see. And I'd rather make intermediate commits that break things and fix it. I could make a separate public WIP branch, but for this, I don't really feel there's much value in people seeing my in-between meanderings and prototyping that I might toss away or never finish. So private repo it is.
The project doesn't yet have unit tests, so that's one thing I want to fix. I also want to work on splitting the compiler into smaller modular pieces, which I've probably talked in another post before. Decided to just rip the entire compiler code out for starters, and phase it in piece by piece. This way, I can put more thought into where things should go this time around. I can potentially I clean up some inelegant things, and can review and make fresh notes about what to improve along the way.
I'm still not sure about it, but I've long hoped to add features that can define platform backends directly in the .wiz language. Wiz already has it so that every platform provides definitions for register sets, addressing modes, instructions, and their encodings. Right now these are done directly in C++, but if these could be moved, that would make maintaining these bindings easier and allow new ones to get integrated too.
With a little bit more work on top of that, it could even possible to allow mixing raw assembly with Wiz-style high-level code. This would allow interop with code written in other assemblers, allowing the inclusion of libraries that weren't written in Wiz, without needing to port their sources.
Another thing is that, Wiz currently targets binary opcode formats directly from its IR, and doesn't have any text dump of the final program code. Having this feature would allow easier verification of the code generated for bug-checking the asm and potentially for writing some functional tests of the compiler.
There's also some language warts I've wanted to iron out, this gives a chance to potentially revisit that in the process.
Lastly, I got a new laptop, an Asus Vivobook Flip 14.
It just arrived after the long weekend, and so far it seems pretty decent.
The 2-in-1 laptop-and-tablet aspect wasn't needed but it's a nice extra. So far, I managed to uninstall the bloatware, disable a bunch of Windows 10 features + apply registry edits, and install a bunch of basic applications for getting development stuff done on it. And there's Chrome, Steam, Spotify, etc.
The half-size arrow keys are unfortunate, but unfortunately all Windows laptops I looked at had some drawback or another for my personal preference. Also, this laptop seemed to have some of the better specs for comparable things of its price. And didn't do things like remove the headphone jack or only have one USB port.
Overall, pretty happy to have a functioning laptop again. It's been a long time since I've been able to do development away from desk.
My previous laptop was from 2013. While still kicking somehow, it has a keyboard that's barely longer usable. They don't make it easy to clean the keys without breakage. It's been like that for about 1.5 years now (basically keys died right after xmas break in 2019). So it's made me do all development work exclusively at my desk. With the pandemic requiring my home desktop to become my full-time workspace, being able to do projects on a different computer, away from my desk is quite nice.
I'll probably keep my old machine as media box until it completely runs into the ground, since it's still possible to type short parts of a url into a browser and then autocomplete and click on things.
Okay, see you next week if I can remember this time! Now, to try to sleep again.
This week was quite uneventful, but I managed to get a little more progress on my battle engine.
I am currently at the point that I need to prototype some code that actually makes the entities move and perform attacks. I'm still figuring out where to go exactly... For now, I think a good way ahead would be to make everything driven by a really mindless "AI" controller. This could issue a basic attack move and picks a target any time they're not currently attacking. Then try to prototype some logic for moving around the battle map, getting characters into range, and resolving the attack moves.
It would be nice if I can push past the "blank slate" problem things are currently at with this, and prototype a rough pass.
I also played more Star Ocean 2.
Getting to the mid-way point of the game and started mastering a few skills to allow breaking open more of the games systems in time. I now fully mastered Pickpocket-related skills on Claude so I can steal items from NPCs during Private Actions (if you do this with other party members in your group, it apparently lowers your reputation with them, so good to avoid that I guess! Pickpocketing your teammates within the town, when your group is only one member seems to be ok though).
Went back to a few towns and gathered some items -- nothing too significant yet, but the occasional nice accessory + crafting resources. There's one crafting item called a Rainbow Diamond I really want to steal off an NPC near the start of the game, but they make it extremely challenging to take. Pickpocketing an NPC only has one attempt each, so you pretty much have to follow a guide to know what each NPC will give you, and restart if you fail on any significant items. Also SO2 was made in the days before soft reset was common on RPGs, so every failure requires resetting the console, or getting a game over so you can reload your save. Eventually I decided I'd call it on attempting some of the rarer stuff for now in the interest of getting further in the game. The pickpocketing is entirely optional, but it yields some items that are hard to get for crafting ultimate gear later.
Eventually, I went back to the main story. I just completed the sword tournament in one of the cities. A story event forces you to lose in the final round to help show off how "cool" your rival Dias is as a sword fighter. I usually don't care for these scenarios in RPGs, but it's one of those ok cases where it's one of those very clear 1-shot wipeouts where you know you can't win.
I also went on a side-quest and recruited Bowman, a pharmacist who can rapidly throw handfuls of poisonous and explosive pills for special attacks. In order to recruit Bowman, you have to gather a rare herb from an annoying cave filled with lots of different herbs that you need to try collecting one-by-one until you find the right one. When I was doing the side-quest, my other characters gained tons of levels, because of the extremely high encounter rate and annoying branching maze-like nature of this dungeon. Using the "Scout" specialty set to avoid encounters at level 10 didn't seem to have any impact. Some enemies in the cave provided a fun challenge but others were just annoying to hit and wasted lots of time targeting. But now that my party is all the way up at Level 45 for this point in the game, my magic characters can cast lots of heavy attack all spells to wipe most annoying encounters.
Bowman joined at Level 25, so it'll take a little to build him up rest of my team. Either way, finally have a party of 4 members, so I guess once I recruit one or two other characters in the side-quests, my party will more or less set up for the rest of the game.
Starting to get a better impression of the game, and it's got some definite rough edges in spots but still enjoying my time with it. I'm hoping now things will start to move faster in this as well, since this annoying dungeon side-quest is over + not needing to grind as much.
I also had a few ideas to work on my high-level assembly language Wiz again (which I use for making most of my personal homebrew projects). Before I can do that though, I really need to work on cleanup + refactoring of the codebase a bit. I have already made a few plans on how to gradually split up the compiler code into smaller pieces so that it can be easier to maintain, but it's always a matter of motivation. Doing this sort of code-cleaning isn't very rewarding to work on, but leaving it to work on new features makes those more tedious than they could be, and makes the mess grow more.
None of these are impossible changes, it's really just sort of burnout and dread thinking of going back to this part of the code. Even though I like the process of creating a programming language and making compiler tooling, it's a different story about re-organizing the internals. It takes a lot of building up motivation to do these sort of tasks, for me, sometimes months away from the project until the right things align. Anyway, it's been on my mind more again, so it might mean I end up going back to it again. We'll see.
Anyway, that's all this week. See you again soon!
Another week went by pretty fast.
I put more work into that battle engine prototype. It's more or less executing the plan that was in-place last week, but not quite to the exciting parts of things yet. I completed most of the basic setup to do spawn a battle formation of player and enemy combatants. But there's still nothing to really look at yet.
I also started structuring data things into different data structures. These are what's in already:
- Game Modes: different possible modes/scenes within the game, that may contain several substates and their own data they manage. Has an update callback as well as callbacks for entering and exiting the game mode (it's also able to react on the mode that is being switched to/from, as needed).
- Entities: things that can be spawned by the game, having a sprite and some data associated with them. Each has an init + update callback for the entity, along with some auxiliary userdata associated with the specific entity -- this can be used to manage the extra data this particular entity type uses. Entities can be connected to many other subsystems like combatants, particles, projectiles, traps/zones, etc.
Potentially the same entity system can be used in both battle + other game modes, but with different entity types, but I'm only focusing on the battle for this.
- Initial Stats: the constant stats data used to load the initial definition of a player or enemy.
- Stats: a bunch of stats used to manage the live representation of something in battle. these have both current and max values of some attributes, such as HP and MP. Other stats are expected to not change. Like FF6, I was planning for players' stats to be largely remain constant, and effects will be scaled by level, and augmented by external equipment / status bonuses. But there will be some things can affect the base stats of the enemy.
- Player Definitions: the constant data defining the initial stats for a given character + other immutable properties for that character.
- Player Instances: instances of a player that have been recruited/added to the story. Has persistent information that it carries along with them, such as the live representation of the player's stats, their equipment, and so on. Some of these stats will possibly be copied into a secondary data structure for combat data.
- Party: contains a fixed number of party member slots, each containing a reference to player instances that are in your current party. (there will probably need to be some sort of "reserve" party too, for keeping tabs of characters you've recruited and are available to the story at the moment. But maybe it could be as simple as a list of party members that are currently available -- have that updated by in-game, and use that info for any party selection menu.)
- Enemy Definitions: the constant data containing the initial stats for a given enemy.
- Enemy Instances: the live representation of the enemy stats, as well as some mutable data associated with their current behaviour and tracking information (eg. possible targets, various counters and timers, managing more complex multiphase patterns).
- Combatants: the pairings of a reference to a player or enemy instance, and reference to an entities. Eventually they will also contain some common state for managing the movement and command execution of a combatant. This mostly exists for places where the distinction between enemy and player doesn't matter as much, such as targetting and common movement logic. Things like damage functions, decision process, additional stats bonuses (eg equipment on players, player-specific buffs, etc) can still delegate these decisions, but functions that take a combatant will wrap these where necessary,
Besides that, I drew a couple tiny placeholder sprites as stand-in characters. Now I just need a couple little enemy sprites and this would be pretty good!
I started replaying Star Ocean 2 since I had never finished that game (although I watched a friend clear it in university, and played through most of First Departure on PSP). I wanted to gather some ideas and research its battle system a bit, so it seemed like a good excuse to go back.
The combat so far is pretty enjoyable and fast-paced, with a fairly chaotic real-time combat. You take control over one party member and the others are controlled by an AI, which can be issued different strategies. Characters can attack with melee weapons, use special attacks (with varying speed/range/cost), shoot ranged magic projectiles that travel across the level, or cast special magic that freezes the gameplay during the effect. Enemies have different attack patterns and movements, and your units will run around chasing after the enemies and doing different things.
The game also has a lot of complicated skill systems and mechanics that let you craft different items categories (metalworking, cooking, etc), identify items, play instruments, paint, pickpocket NPCs, etc. Some skills combine to unlock even more skills, in addition to also having an effect on your character's stats for investing in a particular skill. Some of the skills also eventually combine for even more powerful skills once you have their mastery, allowing you to craft some ultimate equipment or track down an optional boss or something.
So layered together, all of that it gets pretty convoluted, but it's fun and eventually the game systems get pretty broken in your favor if you put enough points into things.
There's apparently several endings and multiple characters you can recruit based on the story decisions you make, and other characters you decide to take/not take with you, optional Private Action events, etc. The final boss has a "limiter" that you can disable before the post-game if you want a much harder version of the final fight with the "true ending". Neat.
So far I'm pretty early, just past the Cross Cave quest and on to the next story area, but I have a few characters in-party now. Also yes, the battle voice acting is awful and it's great. Once I get further in, I'll have a better impression of the "fully unlocked" battle system, as well as hopefully a better idea of how they change the combat to keep thing fresh as it progresses.
To make all this possible, I fixed my component-to-HDMI scaler setup (RetroTink 2X Multiformat) to work with PS1, PS2, and PSP stuff, so now I can play at my desktop computer. and potentially capture videos, and stream if I wanted. Not only for Star Ocean 2 but potentially other Playstation things. I also have Genesis component cables to test with my fixed scaler setup eventually. I had previously only the ability to do this with FPGA clone products of the NES and SNES, and a Rad2X cable for SNES. I guess the RT2X can also take composite if needed, so that gives an option for consoles that only have A/V but not component, even if the picture will be a bit fuzzy. Should be nice to dive into things more, in any case.
Anyway, I'll leave things there for this week. Take care everybody!
So, it turns out that my recovery time for doing a gamejam over a weekend is a bit longer than I thought! That sort of threw me for a loop, and I was running especially low-energy by the latter half of the week. Add to that, there was some sort of less-glamorous-but-necessary tasks at my dayjob and I was pretty exhausted.
I realized I'm still not back up to full energy to write more assembly code. But I worked on something new... that's potentially for an old project! I've started working towards implementing a battle system mockup, that I could use for "nrpg", my NES RPG described earlier on in my posts here.
I had originally wanted to maybe do a turn-based RPG that's fast to navigate and has quick rounds. But about two weeks ago, I had a different idea for a completely different kind of battle system, with realtime elements.
I was thinking about a possible design for a "shmup RPG", with the following:
- real-time action resolution, like an action game (shmup, sidescroller, etc).
- simultaneously command multiple units with an always-visible menu bar at the bottom that has 4 secitions:
- party actions
- (??) autobattle
- (??) special team actions
- run away
- actions for party member A, B, C
- basic attack
- items - shared inventory. consumables, infinite use relics.
- (??) actions can be interrupted up to their execution, and possibly during the execution of held actions.
- each unit has a high-level state related to command progress:
- awaiting command
- moving into position (either a position relative to target, or an absolute position)
- charging (if applicable)
- recovery (if applicable)
- each unit also has the low-level physical entity with its own state management. These states are things like:
- moving to target
- basic attacks
- different phases of magic / special moves being performed
- hurt reactions
- entities move around in real-time according to these commands.
- positioning matters (although movement is automatically controlled by simple AI)
- simple pathing, no collisions/walls in the middle of battle arenas, so no need for A* or something -- simply move in a direct path to the target.
- attacks have designated ranges + targetting logic
- animations could have attack/hitbox and vulnerability/hurtboxes that affect the collision
- projectiles are spawned and move in real-time
- evasion stats that could apply upon either incoming attack proximity, or as a last-minute reaction roll to a projectile collision.
- timed reactions that can be selected from the menu as an enemy
- would probably need a streamlined menu interface to really make this work, potentially limited slotted skills, like SaGa, Pokemon or some SMT games.
- (??) waves of enemies continue to pass by - defeating them could yield bonus pickups that can be immediately gathered and used by party members. Like a shmup, they pass by and you can avoid their attack rather than fighting.
- (??) barriers and protective fields that can placed on the map, to resist or negate certain attacks.
I decided to shelve the actual shmup aspect with ships and whatnot, but trying to see if I can implement the action elements onto a fantasy RPG, in particular my NES RPG. Reducing the scope of the above idea to make it easier to get started, and going to gradually see what is necessary.
I'm currently implementing a system to manage combatants, and an entity system that spawns/updates various things within the battle. Entities will be the building block for several kinds of things the move around and have sprites. They could have extra metadata associated with them depending on if they're combatants, projectiles, traps, barriers, particles, damage numbers, etc. For now, I'm using placeholder art from some older projects, and trying to make stubs/placeholders for turn order, actions, etc. Going from there to block things in.
I want to see if I can mockup an action battle system using this. Failing that, I can reduce the scope to a turn based system later, and some of the same elements may still be useful. In any case, I want flexibility to handle different actions that could comprise of multiple states, and move and spawn sprites for VFXs. So even if the battle wasn't real-time, the turn actions would have many elements that need to be spawned, updated and animated.
I'm using my simplistic C engine, vg, so that managing things in terms of 2D background layers + sprites is pretty straightfoward, and all the input handling and windowing stuff is already taken care of. Everything is written to avoid runtime allocations + loading, and instead uses statically-allocated global arrays, so that it will be easier to port the various subsystems to asm later. I could have used something like Love2D or Godot, but I just reached for a tool I knew would take not too long to get setup. And plus this engine follows some similar limitations I'd need to follow if writing a game on an 8-bit console, so it gets me planning for this ahead.
Going to keep working away at it if the motivation sticks!
Also something I hadn't mentioned on here: I'm non-binary and my pronouns are "they/them". For a long time, I just didn't list anything so people could decide as they want, and I would only fill in people who were closer to me. But I realized I don't really associate anymore with my assigned-at-birth + assumed-online "he/him", and I wanted to do something small to update that.
I decided to list and update my pronouns on my Twitter a couple weeks ago. Before, my pronouns were never listed in my bio. For at least a couple recent years, I have considered myself non-binary but not openly. Without explicit pronouns, and because of my display name "Egg Boy Color" and my IRL name, gender assumptions were formed. And since I wasn't yet open about this, I'd usually go along with the pronouns people used.
As for my choice of display name, Egg Boy Color was meant as a lazy augmentation of Game Boy Color but with "egg" instead of "game". It was a console I was fond of and making projects for, combined with a breakfast item I liked eating. "egg" wasn't used in the queer-coded slang sense, but I guess it could have applied in my case.
I didn't think too much about the "boy" aspect, and still don't. At companies like Nintendo and Sony, there was probably an antiquated marketing decision somewhere around the gendering used in Game Boy and Walkman, but the products themselves are inanimate objects with no gender, and went on to be enjoyed by people of all genders. So I dunno, I guess I figure it didn't mean anything significant but is nonetheless part of the name. Even if my thoughts around my own gender might have changed since I chose my handle, I'm okay with leaving it as-is. At present, I still don't mind my older nicks Overkill or Bananattack either. They're legacy names, but simply retired them for sake of online searchability, and I liked eggboycolor better.
More recently, I mentioned my pronouns at my work, and in a couple other online communities. For me in particular, I don't mind the occasional mistake, but I still would appreciate people's cooperation in trying to remember my pronouns. In any case, I don't currently have any plans to change my online handles or IRL name, or to change my appearance too much, but I can't speak for the future. I have some opinions formulated and others still being figured out, and I'll choose what/if I want to share. But probably not going into much more detail here, as I want this place to continue to focus on my projects!
I'm still new to being more open about gender identity stuff. Anyway, that's a lot of words. It's probably enough to know my new pronouns, and leave it at that! they/them.
Alright, that's all for this week. Hope everyone has a good one, and see you again soon!
Heyyy everybody, it's egg here. Another week has flown by, and as usual things were very busy at work.
But not-so-usual, on this weekend, I ended up participating with some friends in the Ludum Dare 48 game jam.
We made a short game named "Frog", which you can download here!
You're a frog and you shoot bubbles! Descend the depths, find the treasure!
- 2bitcrook - art
- cacciatc - programming
- Kulor - programming
- dustmop - programming
- eggboycolor - programming
Plays in an NES emulator, or on a Famicom/NES/Famiclone that supports VRC6 sound expansion.
The game is pretty short, but considering the timespan and that it's a real NES game, I'm pretty happy with what we manged to accomplish.
Thankfully, we picked the category of Ludum Dare that allowed not only team collaboration, but using existing code. Chris Cacciatore provided his NES-based game engine Veil to work with, and it was pretty fun learning how to write code with this toolchain. Chris, Dustin, and I collaborated on the coding side. 2bitcrook did the excellent pixel art for the backgrounds and frog + bubble sprites. The game supports VRC6 expansion chip audio, and kulor provided really cool music and sounds for that take advantage of this.
It had been a while since doing any sort of game jam/compo, so it was great being able to team up with a few friends to make this. It was a bit tiring at time, as I forgot how stressful fitting things into single weekend can be, but once I found the right rhythm and got used to working in the tools, things started to snap in place. It was helpful to synchronize on tasks each night + morning during the jam, as it let us brainstorm and change plans/limit scope when we were getting a bit stuck.
We originally had a few ambitious plans for the frog and the level layouts originally, with scrolling levels, multiple enemy types, and a tongue mechanic, but we quickly scaled it back. The final game has a bubble mechanic + static obstacles to navigate in order to reach the goal in each room. I'm happy the readjustment happened early enough that we could salvage the idea, and we managed to make some neat levels around it.
Hopefully people get a chance to play and try it out! It's a bit buggy, as with any jam game (especially a crash at the ending, some sprite and physics glitches), but for the time allotted I'm pretty happy with the little platformer creation we accomplished.
Getting to jam was a nice way to recharge motivation for personal game projects. But on the other hand, it was also very exhausting to spend an entire weekend basically only working on that, with small breaks for food + walks. So that's definitely not a regular thing I want to do. However, I'd potentially do another jam if circumstances were to work out again.
That's all for this week! Hopefully soon I can finally dust off my projects and talk about something new.
This week was super busy again!
I overbooked myself to an extent, and had lots of things going on outside of work. It was nice to be moderately more sociable again, but came at the sacrifice of free time for projects work, and a need to recharge afterwards. I guess the weather was nice, so I wanted to enjoy this a little bit. (but done with respect to safety, social distancing, etc.)
Curfew also was rolled back to 8pm here, and that's a source of stress and annoyance too, sometimes requiring me to rework my schedule to fit things in the hours we're allowed to go outside. But yeah, still not a pretty situation here and case numbers continue to climb, and vaccination is still catching up to more groups. Waiting and watching the government updates, and staying close to home a lot, as usual heh.
I also got to work on my taxes... I had started a while ago, but didn't make it too far, and with the Canada tax deadline approaching, the urgency and stress to finish that and make sure it's done correctly is a weight on my mind lately. ...But I didn't finish that either! Some stuff about federal work-from-home benefits that I got stuck on, and I had to wait to ask questions to some friends/coworkers on that and a couple other things... But then I didn't have a free night yet to resume where I left off. Taxes aren't fun/passion project by any means, but they're "work on something" that I needed to do outside of the hours of my dayjob! So it counts for "weekly progress", maybe?
Speaking of dayjob, currently I work as a programmer for Tribute Games, and we've been working on Teenage Mutant Ninja Turtles: Shredder's Revenge, a 2D beat-em-up with pixel-art sprites, and a spiritual successor to TMNT games like those for the Arcade/NES/SNES/Genesis. The game was recently in the April 14th Nintendo Direct, so that was exciting to see! Featured at 11:07 in this Nintendo Direct video -- https://www.youtube.com/watch?v=2RNkRaNfCp4&t=667s
There's this gameplay trailer if you'd prefer something more compact format:
Some of the things I did programming on are captured in these trailers! However, as the game isn't released, I probably am not allowed to say anything much beyond that. But still, it's been very cool to work on. I'm happy and fortunate to be able to collaborate with great people on projects like this for my full-time job, and here's hoping development continues to go smoothly for us. I still plan to keep my posts to primarily about personal things, but made a rare exception for this! (Also if you've never tried, Panzer Paladin are Flinthook are two other games that I worked on with Tribute, if you want to check them out! Plugging over.)
Aside from that stuff, I also had the idea to study some visual effects + animation captures, especially from SNES and GBA games, for research and analysis. I was thinking it could be cool to record some GIFs that first show a cool animated sequence or effect, and then do an analysis that decomposes the effect into its different elements + timings. If done well, this learning could even come in handy for creating new VFX creations for myself, and I could also share the notes made with others.
I was hoping to capture footage, in particular, from Super Robot Wars: Original Generations. This game series by Banpresto has excellent combat animations, and cool visual effects that are comprised of many parts. The Super Robot Wars games are are series of cool mecha strategy games that fuse elements of many popular mech animes, some original characters and even some cameos of Gundam/Neon Genesis Evangelion/etc in certain games.
The series has been around a long time, and characters from the older titles occasionally appear in newer games too. It continues to get new titles to this day, such as Super Robot Wars T (import-only but does have English version through EastAsiaSoft). They don't seem to be released outside Japan and Asian markets very much anymore, but the few games we got in North America are a lot of fun to check out. We got the Original Generation series, and there's also some weird DS spinoff RPGs like Endless Frontier: Super Robot Wars OG Saga too, not sure what outside of that we had.
One game we never got here, for the Super Famicom, was Super Robot Wars Gaiden: Masoukishin – The Lord Of Elemental which looks super cool, and has a fan translation by AGTP. I want to play this someday, but I'm getting sidetracked somewhat heh.
Anyway, here's some SRW:OG GIFs of Kyosuke piloting his slow-but-powerful red mech Alteisen, performing Heavy Claymore + Revolver Stake attacks:
I was hoping to dissect these into timelines, figuring out how much time they spend on each "state", and also figure out what elements comprise these captured segments. I don't have an animation or film background, so it would be explained more from the context of a game programmer who enjoys coding VFX. I would trying to think of things in terms of "systems" they use, their compositions, a possible flow between different distinct states of animation. I could see how different sprite particle effects, screen shakes, sprite shakes, palette changes, blinks, hit flashes, transitions, scrolling backgrounds, character movements, etc are done, and what they contribute to the overall effect.
I also wanted to capture a few attacks from FF6 for ideas from there too. I was hoping I could also compare it against earlier battle FF systems and show the smaller, less-obvious ways in which the battle animations were improved between game revisions.
Anyway, still gathering captures + playing enough of each game to be in a spot that can be captured nicely. Then next comes actually taking notes. Then making still diagrams / text explanations / or smaller explanatory GIFs. I don't have time to do any of this yet, but maybe one day, if I keep pushing it along.
Well, this still isn't what I hoped to have done this week, but this is how it goes sometimes. While I didn't have the energy to do my game projects, I at least did other stuff that. And I wrote a lot of words here again! Maybe someday the stars will realign and I can continue where I left with things on Wandering Magic MSX, it's still regularly on my mind even if it's not moving at present.
And besides that, getting excited for Ludum Dare jam this upcoming weekend! Hoping to participate with friends. I was recently sent a doc by my teammate, that contained a tentative schedule + a guide to setting up with the tools that they're planning to use.
Looking forward to be able to talk about how it went next update! Crossing fingers!
This week was once again very busy for me. I thought a little bit about what would be a good next step for the Wandering Magic MSX port.
In particular, I was thinking about trying to implement a subset of the enemy movement logic for starters, rather than trying to do a large line-for-line port of the entire behaviour at once. This way, progress is divisible into smaller, measurable chunks that can be tested and verified more easily. Trying to convert the entire function, although small and simple in Lua, is still a large undertaking to port all at once to assembly.
This approach sort of stopped development dead in its tracks a bit, because trying to port things was done without an immediate goal in mind anymore. And when my time is so limited, any loss of clarity is translated into wasted time before warming up enough again and getting somewhere. A consequence of this is, I suddenly feel less inclined to work on something because I can estimate how long it will take to get started, and know that the overhead to pay just to get started again is too much.
So, I need to come up with strategies so that it takes less time to resume the project. This ways it's easier to shelve changes in the middle of something and come back. And I'll still know what I'm doing, and I'll know I have enough to make an attempt at the next piece.
I was thinking of a better idea:
- Start with just getting slimes that move in a random direction.
- Then try having them change this movement direction when a collision is encountered.
- Then add an expiring timer to the directional movement, so they re-evaluate their direction every couple of seconds.
- Then worry about collision detection between the player and enemy.
- Then add stuff to do with damage resolution, then experience+gold on death, then knockback forces. etc.
The gist of this is, more itemized, short tasks with clear end goals. Rather than "here's a function let's rewrite the line-for-line equivalent", without consideration for context and inevitably getting details wrong. This is easier to maintain things within my sparse free time/motivation on nights and weekends. And it might be easier to pick a specific task to show on a development stream, if I decide to do another stream on Twitch.
Nothing is perfect, and some tasks do require deliberation and planning, but by focusing on low-hanging fruit, and incremental tasks toward a bigger picture goal, more work can hopefully be accomplished that will push things ahead. And the goals/tasks can evolve in response to the changes made, rather than speculating and planning in a vacuum.
Anyway, so yeah would be worth giving this approach a try. Even just getting "pick a random direction and go in it" isn't super simple, since it requires some code being already written, namely both movement code and a pseudo-random number generator.
In this case, I already coded a Galois Linear Feedback Shift Register for doing randomness, in 6502 and GB assembly, so the translation to regular Z80 should be pretty straightforward. These randomizers are pretty short in terms of code, and have maximal periodicity for its bit depth, so they're kind of a nice balance between "good randomness properties" and "low implementation cost". Better randomizers exist, but these are some of the easier to write.
To seed the randomizer, I plan to simply use a fixed seed on startup. But I will step the random sequence every frame, so over time the sequence diverges, depending on how many random values are sampled between gameplay choices. This means speedrunners can still get their frame perfect randomness (not that I anticipate any for my games, but...), and meanwhile normal players will still see enough random to feel that the game has some unpredictability/chance to its mechanics.
On top of just pure random, I typically like when games do stuff internally that behaves like shuffling a deck of cards and dealing those out, only reshuffling when the list is exhausted. Also, counting duplicates and choosing another action if one is used too much. this will also mask any crumminess in the RNG since it's much easier to shape the random to something more pleasing to players. It prevents hitting the degenerate cases as much, by encoding rules that ensure each event has a finite number of occurrences, or a decided-once order that is then consumed.
Anyway, I got a little detoured here! adding randomness, and then adding a slime moving around that turns when a wall is hit, will already feel like a great start. Maybe by next week I can get this delivered. We'll see!
Even while being blocked on my project, the MSX was still on my mind however.
I started playing around with taking some old art of mine, from a project called FROG EGG. I started imagining what it could look like in an MSX1 art style.
Then I made a mockup with a water background. My goal was to see if I could make a scene that had 1-bit sprites over a somewhat colorful background (instead of black bg), and be mostly readable.
Here's the original 1-bit game this was based from:
The original game was a game for the Arduboy, a small Arduino-based AVR handheld system with 2K of RAM, that has a 128x64 resolution and a dpad + 2 buttons.
I ran into a snag though, in that, there is limited RAM + ROM space. Worse, if you go beyond a certain limit, the flash loader on the Arduboy gets bricked, and requires you to do the tedious work of factory resetting the device with a paperclip (easier said than done, from experience, even with the tools, because the reset button is inset pretty far and you need to hold it for a few seconds). Anyway, maybe one day I could make a small adventure out of the engine I did... it just got very precarious to make code changes which is not something I really wanted in a project in the prototype phase. (I eventually made an SDL wrapper of my engine for easier testing + sharing with non Arduboy users. That made things considerably easier, but still shelved things until I had a better plan formulated... And by then other projects came up on my radar lol... maybe one day)
Anyway, at the moment, I have no plans to make a platformer with this art yet. However, I thought it could be fun to create more of these little mockup scenes like the above MSX one, with some background pieces + some different sprites. Stuff like forests, caves, cityscapes, ruins, etc. Possibly more in the MSX style as well. If enough areas were done, it could be neat to explore making a game out of it. But until then, happy to just explore making some more art and keeping my pixel art from getting too rusty.
In addition to the above, I heard that Ludum Dare 48 is coming up soon! (the weekend of Friday, April 23 - Monday, April 26)
I might enter the Jam with some friends, since it allows collaboration, and they allow bringing in existing code+art+assets. I'm always busy when LD comes around, but in this case, I planned ahead and tried to clear plans to ensure a greater chance of successfully working on something. Never tried the Ludum Dare team jam, so it will be fun! Last compo/jam I entered was a few years ago, and the last collab was even further back than that. I'm really bad at entering these, but giving this a shot, since 1) the timespan is short 2) I have the time available 3) I planned time a couple weeks in advance.
Anyway, catch you later, hope everyone has a nice week! Next Gruedorf post will likely adhere to the later schedule I usually post in (Tuesday @ ~12:30 AM EST). This one was posted a bit sooner since I am busy tonight.