Oli's old stuff

Tinkering with retro and electronics

Oct 27, 2021 - 7 minute read - spectrum cpc z80 retro gamedev smeg

Rebooting SMEG for the Amstrad CPC

Out with the Old

I recently started messing about with the Amstrad CPC 464 to learn how to code on it. Specifically questions such as “how does the screen ram work?”, “how do I move software sprites?” and “how does input work?” etc.

To speed up this I wrote some code to convert some of my early SMEG sprites into CPC pixel format and started plotting them and moving them around.

This turned out to be a pretty enjoyable thing, so I progressed into “let’s make a CPC demo”. I ended up grabbing some of the basic code to do with input handling from SMEG and porting it to the CPC.

I then asked myself “what would it take to port SMEG to the CPC?”. Instead of copying and fixing, could I “start again” with new tools, building system by system and cherry-picking where it makes sense?

The answer to these questions is yes. It’s an opportunity to address the flaws of the original and not worry about “breaking stuff” along the way.

Tooling

Some of the main issues I had with the original was that the tooling really sucked.

Room Editor

I love Tiled Map Editor but it really wasn’t a good fit for this game.

I decided to start with LDtk and experiment a little. I can already say that this tool is excellent and fits nicely with my workflow.

  • I can define “entities”. This lets me have a uniform object structure for all interactive objects in a scene. I can mandate properties, set defaults and otherwise do things in a much nicer way
  • I can define a “world”. The whole game is contained in a single LDtk project. I can lay out each room and have them connect together. This makes a huge difference to workflow as everything to do with the world is in one place; letting you hop between rooms and entities really quickly
  • I have created a “global” room with a config object. This lets me have links to external files all in one place, so I can parse one project and jump off into all additional resources. Before I was using a json file to deal with this.
  • I can define the same set of layers for each room. This lets me have a standard set of “foreground”, “background” and other such things like “mask” layers too. This has been a boon to workflow.

Scripting

So now I have a nice editor flow, I decided to look at some of the other things that I didn’t like about SMEG v1.

The approach I took to scripting in SMEG v1 was:

  • each object had a script associated with a verb. This meant that managing scripts was “all over the place”. There were snippets for the same object in different locations
  • I hated the “TCL-like” language I created. I did previously look to create a BASIC dialect but ended up throwing it away because it didn’t fit into the old codebase very well
  • I had inlined the scripts into the object properties; this gave me a terrible editing experience overall as I had to write code within the map editor. As this was largely just a text box, this was not good.

This time I’ve decided that “assembly-like” is the way to go. Each object can have only one script attached and that script lives externally in a separate “smegasm” file. This file is parsed in one sweep and contains a “verb table” that essentially says which labels to jump to for that verb.

This lets me edit in vscode, which is fantastic - and it also makes a script “self contained” for a given object. I can now also share code within verb actions as it’s just a jump to different places in the same code block. I can define local variables and have them all sit in one place. It’s a relatively simple change, but it’s a big improvement over the previous iteration.

Similarly, I also now have a single “Room” entity per LDtk level, this also allows for a script to be attached. I can handle “on enter”/“on exit” type events here in a similar way.

Text and Dialogue

I decided to bite the bullet and move all text and dialogue out into it’s own resource file. This is a toml file (aka json-like structured ini) and is essentially a set of “scoped” key->list of strings. The scope would be room.name or object.name, etc.

The rationale for this is that I have all of my text in one place, again removing the “scattered everywhere” type problem I have with scripts. If I want to see all dialogue for a room or object, I can look here. The next big reason is that it makes localisation possible. Should I ever ship anything, it would massively improve the ability to port the text over to another language without going through every room and every script. Just edit this one file and recompile the project.

I’m also looking at how I can take some of the approach that Ink uses for defining the progress of conversations and present dialogue options. My current thinking is that the “flow” is handled in the script and the text itself is just text.

One thing I’m looking to add is “control codes” to the text, so that the text can refer to objects/actors by their “script names” and have either the build process substitute it, or the game do a dynamic lookup when it’s building the text for display purposes. This would let you have things such as “It’s a ${obj:thing}” be a default text option that’s shared with many objects.

Engine changes

Animation

One thing I am looking at overhauling/redoing completely is the animation system. I’ve not got any firm plans for how this will work, but the high level idea is to decouple actor / object from image/animation. Similar to SCUMM’s ‘costume’ system, I guess. I may also look at splitting animations into “segments”, so things such as talky heads can be handled separately to the body. I had a hard coded system for this in SMEG v1, but it broke down almost immediately when I tried to use it on a different actor type.

Data Formats

I’m writing everything to “compile” down to a completely different data format.

SMEG v1 used a system whereby I emitted assembly-friendly files with labels, etc. This helped debugging but I ended up leaning too heavily on referencing labels from code, thus coupling the content and engine in places that they shouldn’t have. Actors and animation was one of these systems.

Another issue this approach created was to make the content non-retargetable. A table contained pointers to other memory locations, so I had to load everything in one big hit. I couldn’t easily swap stuff in and out, or decompress on the fly. This time I’m aiming for the data files to be self-consistent; with offsets being used from the tables to the content within them, or with externally referenced assets being tied by an ID. It puts a little more processing on the runtime, but it’s going to make it far easier to do things such as compressing rooms/dialogues/sprite packs that aren’t being played right now. Should allow me to do more with the memory I have, as well as being able to load more content from disk (or tape) if I need.

Next Steps

The plans for all of these changes is to give me a new base that’s easier to work with, but also to help isolate the “core” from the system. The intention is that SMEGCPC will get some compile time switches that let me target the Spectrum again, essentially letting me have the same set of tools and engine but target the two different systems.

I’m using MODE1 graphics for the CPC, so they’re not going to be supremely colourful. The screen size and format is more compatible with that of the Speccy too, so this makes the process possible.

Game

I’m working on a new game that’s not based on Red Dwarf; it’s something new entirely. I will consider picking up the original idea eventually, should this new thing see a release. There’s a few reasons for this; one being a complete “break” from old vs new, but the other is to lower expectations for people following the project.

This is also the same reason why I’m not going to show anything until it’s ready for playtesting. It helps reduce the personal stress of that expectation and anxiety about getting creative fatigue on something people are “looking forward to”.

That’s all I have to say for now.

See you smeggers next time.