I really do have some more interesting posts brewing currently, but they still need a bit more time. For example, as I’ve translated further parts of the engine, my concept of how sprites function specifically has changed, and may change again as I get closer to when I plan to translate the sprite drawing routines (currently I plan for this to be when I implement the main screen drawing routines). I’ve also been continuing to ponder and experiment with how best to conceptualize the translation process, as well as the structure of the engine itself. I think they will be very interesting, but for the time being I’ve been spending my available time on the code, so those posts will have to wait a little bit longer (I’m sure everyone is dying to hear the next programming related poem I feel compelled to write down off the top of my half-asleep head late into the night :P). With that being said, on to this weeks update:
It’s hard to know where to start, because quite a lot has progressed since last week, but of that is just the actual code in functions and is pretty useless to see without context. However there has also been a lot of progress on the conceptual side, not least of which is my internal picture of the game engine as a whole. In fact I will begin with that, because I think it is arguably the most important progress I made recently. Until recently, it has been difficult to get a sense of the size and scope of different aspects of the engine, or even just how different files and data structures fit within the game in general. However, partially as a result of the further translation (logic.gs specifically), and partially from simply looking through each source file and evaluating their structure with new information so that I could put them together into a visual map of the engine, I think that I now have a pretty good idea of what’s in the engine and what the scope of each subsystem is.
This seems like it should be a straightforward task on paper, but the trouble with mapping out the interconnections and scope of a game in assembly is that source labels and terminology are not always what you expect them to be. This is something that I have identified as a potential problem, which I am trying to avoid whenever I notice it. It is easy to view things by default with a modern lens, even when you don’t mean to. I didn’t expect this to affect me as it has, because I have spent so much time with lower level languages, but I have found myself occasionally making assumptions about the way the game engine works based on terminology and concepts that are taken for granted today. For example, the terms Object and Class carry with them concepts of encapsulation and structure, when looking at them through a modern lens. But In assembly, especially in the 70s-90s, not much can be taken for granted. Maybe the term was used to denote a loosely defined scope for certain data. Maybe it was used as a reference point for other people reading the code. Maybe it was leftover comments from a macro. Or maybe it was one thing at one time, and changed as the logic of the game changed. A game like this exists in an ocean of memory, where the idea of encapsulation is as restrictive as a rope lying on the surface of the water to separate one side from the other. Could a swimmer in this ocean see the rope? Sure. But they could always choose to swim under it if it’s more convenient. In the same vein, it is easy to see something that looks like something we know, and without realizing it attribute properties that come from modern sensibilities. Only to find that if it walks like a duck, and talks like a duck, it could just as easily be several other things that have no inherent interaction with each other but when viewed from the right angle look vaguely like a duck. Or maybe it’s a goose, with many similar properties and functions as a duck, but which is still distinct. Sprites are a good example of this, as will hopefully be made clear in a future post.
When I do catch myself looking through a modern lens, I need to remind myself to let the engine itself be my guide to its structure. In other words, not get ahead of myself. So with that in mind, I laid out what I think is a good representation of the ‘scope’ of different parts of the game, based on how the game treats those parts, not just what it calls them. I will have some kind of visual for this in a future post, for now it’s just paper drawings. I’ve also been using that to look forward in terms of planning milestones and gauging progress. I have been doing this through a different kind of diagram (yes, I make a lot of diagrams, I’m a bit of a visual thinker if that wasn’t obvious :P), which organizes the game engine by ‘layers’. The layers are determined primarily by scope, but also by their function in relation to the engine, and the relative priority of that. This layer organization is how I have been structuring my movement through the engine, and should also make it easier to avoid seeing geese as ducks, to tie this back to the previous example. You’ve probably heard the term ‘vertical slice’ before, but for my purposes here it’ll refer to something that touches many of the ‘layers’ I just described. The idea with translating by layer, is to avoid trying to implement the whole of something (an object, structure, concept, etc.) by following it through multiple layers. I think this creates a negative vertical slice of the entire engine, because if we do not have a full picture of the individual layer that part of the slice is coming from, then we might not be implementing that aspect correctly, and worse we might make assumptions about the entire engine from the parts of each layer we see, that we would not have made if we had translated the layer first. This is getting a bit tangled in analogies, so I’ll just leave it at that and hopefully some diagrams in the future will make it a little more clear.
In terms of other progress, I have been continuing to fill out kernal.cpp, but I have also made the skeleton of logic.cpp, which contains the gamestate loop, and have been filling in the functions used in that. Along the way I’ve been adding to sprites.cpp and immortal.h, and I set up the files I will need for the future according to the organization I’ve been talking about. There’s not much point in listing out all the functions I’ve added or changed, as there are a lot and they won’t mean much without context (I translated the health bar code for ex, but the sprite drawing routine at the end of it isn’t implemented yet so it doesn’t look impressive for example). But in the future post about conceptualizing the engine, I will likely include my list of functions and their state of implementation and whatnot.
Also, there’s some neat debug stuff in the engine. I should talk more about that at some point. Recently I found that there is a routine which allows the developer to progress the game frame by frame, at will, with no outside debugger. Very powerful tool for testing, so much so that I translated it and left it in the engine for the time being.
I apologize for the lack of neat visuals or gifs or anything. I’m quite tired from this week and frankly most of the work I’ve done recently just doesn’t have a visual component. The conceptual stuff will be visual, but it is still in the works. As for what’s next? The evaluation is coming up very soon. In about a week and a half from now in fact. Before then, I have a couple of milestones to finish up, and then the next step from there is implementing ‘Level’. If immortal.cpp is the ScummVM engine, and kernal.cpp is the game engine, and logic.cpp is the game state system, then level.cpp will be the interface between the game state and the room, which contains the objects and interactions moment to moment. In terms of layers of processing, it can be seen as immortal>kernal>logic>level>room>monster.
Okay, thanks for reading!