Uh, what happened? I haven’t posted here for a few weeks. Long story short, the CPC cartridges turned out to be a very deep rabbit hole.
It basically allows you to have a lot of ROM –and memory is always scarce in 8-bit systems!–, so I went back to try an old idea that I discarded –and instead, I made the Dawn of Kernel, which is not a bad thing!–. I haven’t told too much about it publicly, and the main reason is that I don’t know what I’m doing, so the chances of failing are higher than usual. In fact, I have failed already –I’m on a second rewrite of the thing–.
In reality there shouldn’t be any problem with showing what are you working on, isn’t it? Sometimes things don’t work out as expected, and projects get cancelled. That’s OK, but then there is the Internet and people getting excited, and you may end with projects on your name that don’t exist and never will! For example: Moonstone for the MSX was abandoned and kind of became Night Knight –again: not a bad thing!–.
So over my short career as reto-gamedev, I have learnt to wait and see until I’m reasonably confident that I can –and I will– finish a project before getting people excited.
And that explains, partially, my lack of updates here: I’ve been having fun with this secret project –something may have leaked on Twitter, but it is still secret–, but I haven’t reached that point where I know I can finish a game.
Other than that, I have ported most of the unnamed CRPG game –it needs a name!– to use cartridge. This has been a very good exercise, for several reasons. Fist of all, I’m cleaning the code that was starting to look bad, and secondly I’m finding that not all is magic and rainbows using cartridges. I have a couple of solutions for the main issue, but it is definitely a risk factor. It doesn’t help either that SDCC doesn’t seem to have proper bank support for Z80.
As part of those changes, I have researched –and properly understood– screen splits on the Amstrad CPC, because it was bothering me a lot how hacky my wall of messages was. Now the bottom on the screen is fixed to a memory address and I have to write to it only once, independently of what memory address I’m using for the main area of the game –and this helped to push me further down the rabbit hole and the secret project–.
Finally, the progress on “Outpost” for the ZX Spectrum 48K is good, and you should know that because I released more videos of its development. These videos are fun to make, but I need to be in the right state of mind with a planned feature to implement, and I some quiet at home so I can record. Not easy!
I got to the conclusion that these work better as actual streaming, and when a session is specially inspired, that video could be preserved on YouTube. My current approach is probably the opposite, because I try to make the videos so they are good to share. In any case, the response of these videos is quite mild, so I’m not too excited to make more, considering that they require a lot of effort and slow me down in the making games part.
When the CPC boots from cartridge, our code will start executing at address 0x0000 and we have the first 16K bank mapped on that address (lower ROM, in case you want to check CPC documentation).
The strategy that I’m proposing is the following:
Address
Size
Type
Function
0x0000
16K
ROM
Code
0x4000
16K
RAM
R/W Data
0x8000
16K
RAM
R/W Data
0xC000
16K
RAM/ROM
Video memory/Mapped cart bank
You may or may not use a back-buffer with hardware (e.g. in 0x8000), but considering that we can have all our read only data in ROM, 16K for just code is probably enough.
Thanks to the properties of the memory mapping on the CPC, when we map a bank of ROM into lower ROM (0x0000) or higher ROM (0xC000), reads will go to ROM and writes will go to RAM; and mapped ROM is only seen by the CPU. This is important because the gate array can only see RAM when drawing the screen.
This is great, because we can map a bank to higher ROM on 0xC000 and write to 0xC000, even having video memory active at that address, and we will be fine because those writes will go to RAM –and is RAM what will be displayed on screen, not the mapped ROM–.
So the idea is mapping on higher ROM any of the banks as we need them, and we can use that data with RAM from 0x4000 to 0xffff, leaving on lower ROM the bank 0 with our code.
In the case of the CPC plus cartridges, there’s nothing to do, but in the Dandanator we need to configure the cartridge to support this behaviour. We can do it like this:
; SDCC syntax
; the byte pointed by iy will be overwritten
dilda, #0x8a
.db0xfd, 0xfdld0 (iy), aei
We will run this once at the start of the game.
Then we need a bank set function that takes the bank number we want to map in higher ROM. Let’s look at the CPC plus cartridge:
; SDCC syntax
; defined as __z88dk_fastcall in C - parameter in l
dilda, l; cart slots 0 - 31 start at 128
or#128
ldc, aldb, #0xdf
out (c),cldbc, #0x7f80
out (c),cei
And the equivalent code in the Dandanator:
; SDCC syntax
; defined as __z88dk_fastcall in C - parameter in l
; the byte pointed by iy will be overwritten
dildc, l.db0xfd, 0xfdld0 (iy), cei
Finally we need a function to unmap the higher ROM and have regular RAM on 0xC000. In CPC plus cartridges is done with:
; SDCC syntax
dildbc, #0x7f88
out (c),cei
And in the Dandanator:
; SDCC syntax
; the byte pointed by iy will be overwritten
dildc, #32
.db0xfd, 0xfdld0 (iy), cei
It is as simple as that!
Of course that the Dandanator has more functionality than what I’ve shown here, but if we hide these differences behind some preprocessor directives (e.g. ifdef), we can write the code once and generate both types of cartridges without any other changes –tip: look at my CPR tools to generate cartridges; using raw and padding flags gives you a Dandanator–.
And that’s all! This post is result of my own research and I don’t consider myself an expert, so if you find any issues with the text, please let me know.
Update: I added a comment in the code to remember that the opcode used by the Dandanator to process commands will overwrite a byte, so be sure that iy is pointing to a safe memory address.
The Amstrad CPC was discontinued in 1990 –that’s 31 years ago, and we will see why that’s relevant–, and the main media to distribute software was cassettes and 3 inch floppy disks. The Plus models, including the GX4000 console, introduced cartridges (in fact, the plus models don’t have an on board ROM with the firmware, and it was provided in a cartridge instead).
Despite being in 2021, cassettes are still available. There aren’t that many companies selling them, but I would say that for now the situation seems stable. The only downside is that, putting nostalgia aside, as media isn’t great. Cassettes limit the type and size of game you can make, and don’t work well for multi-load games.
The 3" disks where intended to rival Sony’s 3.5" floppy system, and we know who won that one, so the media used by the 128K models have been out of production for years and is increasingly hard to find new disks. The prices are up, and it is old stock, meaning that the media may have physical issues. We also have to remember that 3" disks won’t work for tape-only models without and add-on; and you are still limited to the 64K memory on board, unless you make your game multi-load from disk –not as bad as cassette, but the wait times are still something to consider–.
There are also ways of using a 3.5" disk drive with CPCs, but this is limited to 128K models and I would put this option as something that only the most hardcore CPC fan will do. At least the sales of games supporting this format suggest it isn’t very popular.
Cartridges, as originally intended, have a protection with a special chip that prevents third parties from producing cartridges; and those usually have features for the Plus models that aren’t backwards compatible with the regular CPCs.
We know how to bypass that protection now, so it is possible to produce Plus cartridges; but there’s still the limitation that it is intended to the CPC Plus models only –the CPC models don’t have cartridge slot, only a expansion port that is not really meant to frequently plug and unplug cartridges–.
The CPC was designed to make it easy to be expanded using ROMs, and that has been a common way to load software into the CPCs for a long time, is just that is not very convenient and it requires a higher level of commitment from the average Amstrad aficionado as it needs an expansion where you can put the ROMs. Fortunately, in the last few years things have changed.
I’m not going to write an history lesson here –I know this post may look like it already–, so excuse me if these aren’t in chronological order or if I’m missing other options I don’t know about:
Dandanator mini –page only in Spanish, as far as I know–: is a cartridge format to be plugged in the expansion port that provides a number of generic and advanced features, including support for 512K of ROM (in 16K banks), and it works on any CPC without jumpers or special configuration.
DES: the Dandanator Entertainment System, which is an interface that goes to the expansion port and supports cartridges. It has the same functionality as the Dandanator, with the difference that the expansion contains most of the functionality, and the cartridges are simpler –and cheaper–. It also makes it easier than the expansion port to plug and unplug cartridges, and these use the Game Boy Advance shells –that are cheap and easy to find–. Perhaps the only downside is that you need to buy the DES expansion, and then cartridges for the games.
Plus2CPC: this is probably the newest of the three and provides a cheap way to plug CPC Plus cartridges on any CPC and, as long as the cartridge doesn’t use any Plus features, it will work. It also offers 512K of ROM, just like the Dandanator, and uses the regular ROM mapping functions of the CPC. The Dandanator provides much more functions, but if we only look at storage, this is almost equivalent. The boards for CPC Plus cartridges are available, but not the shells (as far as I know).
So these would be three different options to distribute software in cartridges for our physical editions, and they work for all CPC models –although the two Dandanator options don’t support GX4000–. Not as cheap as cassette or 3" disks, but is instant access to 512K, and in the case of Dandanator, there are extra features –e.g. the mapping is more advanced, or saving data in the cartridge–.
The Dandanator design is public domain and anybody can build and sell them –not sure what is the status of the Plus2CPC–; which makes them more or less available, and supported by different emulators. And this is another requirement for me because: what if you don’t have the hardware?
Currently CPR files –the format for Plus cartridges, which is a container for 32 ROMs of 16K– are supported by any emulator that can emulate CPC Plus models, and the Dandanator images are supported by several popular emulators as well, so it wouldn’t be too difficult for people to enjoy the games without an actual CPC. Besides, there are modern hardware add-ons that support some of these formats –for example, the M4 can load CRT files; and of course the C4CPC for the GX4000–, meaning that you can still play the games in real hardware without having the cartridge itself.
If the games abstract the ROM mapping code, it is trivial to make the same game work in both CPC Plus cartridges and Dandanator cartridges, and it is trivial to generate CPR and Dandanator ROM files.
I’m not sure what would be the response from the community. We have seen a couple of releases recently that were Dandanator only, and these had a mixed response –the games are amazing, it was more people not having Dandanators to play them on real hardware–, and one that was CPR based (probably the best vertical shooter on the system: Alcon 2020).
I would expect that, having not too expensive and easy to use physical releases, plus the digital version that can be played with different options –both emulated and real hardware–, the CRT/Dandanator duo is probably the future of media for the Amstrad CPC. I don’t think I have capacity to fill all that ROM space, but it would take me less time to make better games, because I wouldn’t waste time wrestling with memory limits and I could use techniques that are usually unviable because they require lots of memory.
I have been investigating both CRT and Dandanator, and I can’t promise anything, but watch this space –just in case–.
It is Thursday again and looks like I have time for a early morning entry on the series, so let’s do it!
My Canvas 2D engine
I got to the point where the engine does most of the basics; which in reality is not much considering that there is no game. I have an idea to make a simple platformer with procedurally generated levels –why make things simple?–, but I got stuck when I tried to draw some graphics.
I do have some tiles that are OK, but they are not very inspiring and I suspect the end result would be too bland. In reality it feels like the type of programmer art you would expect in a game jam, so I’m not too excited.
I put it on ice until for now. Perhaps I should get some palette/restrictions from an 8-bit machine and use that as style. I’m not a big fan of modern games that looks like a ZX Spectrum game but obviously is something that would be impossible to implement on a ZX Spectrum, considering that I can make ZX Spectrum games.
It is possible that I’m overthinking this and instead I should decide that is that I want from this project. Is it just making a simple game using modern-ish Javascript as a tech demo? Is it making a platformer with procedurally generated levels? Is it a prototype to test ideas that later I could implement on an 8-bit system?
It could be all of them, but I don’t know!
Work on Outpost
After I started the combat in my unnamed CRPG –seriously, I need a name–, I programmed the PC movement and I didn’t like too much the code structure, so I decided to walk away for a couple of days.
Then I fired Outpost and… I like how this looks! The engine is solid and there are so many new things I haven’t programmed before that I feel I should finish and release it.
So I’m back to do level design, and things are looking promising, actually.
I have designed 8 objects, most of them to be used as part of a puzzle, which works more or less as “key/door”.
Perhaps the most obvious was doors –of course!–. These require the access card, and once you have it you can open them, but only in one direction –we are not going to question the overall design of the “Outpost”, are we?–.
I have some potentially interesting ideas for another 4 objects, but I still need to come out with some story more than the vague idea I have. I implemented terminals essentially to show information, perhaps as diary entries, so I should use them!
ubox MSX lib has CI
Arguably this is something I could have implemented in GitHub as well, but I think GitLab is slightly easier, so thanks to the initiative of Pedro de Medeiros –so far the only external contributor to the project–, we have added continuous integration to ubox MSX lib repo in GitLab. Currently it only compiles everything, but that’s enough for now, because it helps us to ensure no change we make will break thins that bad.
I’m thinking what can we test, really. We could run unit tests for code that is Z80 independent, and that could be compiled with a modern compiler and run in the CI containers, or we could use a Z80 emulator –doesn’t have to emulate and MSX really–, and generate Z80 and run it in the emulator.
Both sound like good strategies, but before committing to write a lot of code, I would like to be sure there are tests we can/want to write.
Titan support in SpaceBeans
In not really gamedev news, I’ve started implementing support for Titan protocol, which is a simple extension to Gemini that allows uploading files. It is one of those idiosyncrasies of Gemini, where extending the protocol is a no-no, so instead people come with these “alternative protocols” that is basically and add-on that could be part of the main protocol.
Anyway, it shouldn’t be too hard to implement, and considering that Lagrange browser supports it, I think it is going to be a nice addition to SpaceBeans. You could manage your gemlog fully from one single application!
Someone posted a link to Underrun, a JS13K entry by Dominic Szablewski, and I was impressed by the game –despite being a jam game–. So I checked its source code at GH, and a couple of things caught my eye.
First of all: how clean and simple –it is not– all looked! Very readable, despite being a game aiming to provide its functionality within some challenging space constrains (13KB!).
And secondly, turns out Javascript has classes now, and my last attempt at the language was before they were introduced in June 2015 –and adoption by browsers happened around Q1 2016–.
It is not a secret that I don’t like Javascript, but with things like Canvas 2D, it is an OK-ish language for game jams and quick prototypes. Actually, I finished two Ludum Dare using Javascript, being my last attempt 7 years ago, and the code for that one is public.
Back then I defined my own idea of Javascript, limiting what parts of the language I wanted to use, and using some techniques to have “classes” and inheritance.
For example:
varA=function(property) {
varself= {
prop:property };
self.init=function() {
// the constructor is this
returnself;
};
self.say_hello=function() {
console.log("Hello");
};
returnself.init();
};
vara=A("value");
a.say_hello();
To be honest, I don’t remember exactly how, but I had inheritance, private properties, super functions, etc. And it did work, actually.
Since then I have played with some ideas with Scala.js –by porting, more or less, my old Javascript code–, but I found that the functional part of Scala was getting in the way. At the end of the day, I liked the prototype-y feel of Javascript, and using Scala I tried to be functional and, although it is fun, it is also very distracting.
So basically I enjoy using the tools and writing the code, but I haven’t made any games with it; which is the actual point of it! Also, I’m not too convinced on how heavy the compiled code is –Scala compiled into Javascript– because, again, it goes against my idea of a short lived project that you get out of a game jam. It doesn’t need to be Scala-rock-solid.
At some point, I also looked at TypeScript, but I found it adds too little and I hate the Javascript tooling, so I thought: may be Javascript has improved now, they are making an effort with the classes, isn’t it?
Well, not completely, but may be close enough.
I have rewritten my Canvas 2D codebase to use “modern-ish” Javascript, and I think I’m going to push forward enough to make a “jam-type” of game. So far I’m enjoying it –despite Javascript; like having a typo and DoSing my machine because Firefox started allocating memory in an endless loop–, so we’ll see how it goes.
For now the classes are mostly worth the effort. There are some “gotchas” part of the classic Javascript, like the use of this, but nothing that is not manageable. And turns out my Scala knowledge is giving me some answers that I don’t think I had back in 2014.
For now, my only issue with classes has been using methods as callbacks. The problem is with this not being bound to the instance of the class when called by a callback.
For example:
classA {
resize() {
console.log("We are being resized!");
}
run() {
// won't work! this won't be bound when called :(
// window.onresize = this.resize;
// instead, use a lambda:
window.onresize= (ev) => { this.resize(); };
}
}
vara=newA();
a.run();
The solution is not too bad: just wrap the call on a lambda, and this will be bound on that context, so it works fine.
I have read some people suggesting to not use this at all, and I see some issues perhaps when using a minimizer because I won’t be able to “minimize” this –unless it performs some trick using a local variable pointing to this–. For now it is working as expected and the code is easier to read and remember, because I don’t have to do my own Javascript to make the language usable.
I have a couple of ideas I would like to implement, and they may lead to a game!
This week should be more DevOps than gamedev, but for obvious reasons –it is a series!–, I’m keeping the name.
I’m in the middle of reworking my personal server infrastructure. As result of my time at Memset I still enjoy one of their ex-employee perks –a free VPS!–, but the company was acquired and sadly the future is uncertain. It is still the same company I knew, to some capacity at least, but I don’t feel completely comfortable having critical services in there without being a customer.
I have decided to double down on Digital Ocean –I already had a box with them–, basically because I can get nice features for free, like a VPC between my machines in the same zone. It is cheap, perhaps some things are not as good as the stuff I built back at Memset, but I got to the conclusion that the pros outweigh the cons.
So I’ve been using a good amount of my free time to plan, setup, migrate, etc; and I’m not finished, but getting there.
On the dev side of things, after I released a bugfix version of SpaceBeans –my Gemini server–, I worked a bit more in my “Cherrygrove City Pokémon Center” CGI script and released it as open source. And now I realise that is only available in Gemini. Oh, well; it is not too exciting –in fact it is really a pokedex, not a Pokémon Center–, but it was interesting making a CGI using plain Python base library, without any fancy abstractions –I used to work a lot with Django–.
Anyway, not a big update, but sometimes that’s life. I’m planning to start combat in my unamed CRPG game, that definitely needs a name, when I clear a bit my DevOps backlog.
Looking great already, and as it’s my favourite genre, and rather under-represented in modern gamedev, I sincerely hope you can get it over the finishing line. But I can imagine it might be a long and arduous quest :)
And they are right. However, the problem in my opinion are the side quests. There are so many things to do, and so many things you could do, that is easy to lose focus and get distracted. And that can contribute to the game never getting over the finishing line.
Besides, there are things that I may want to do out of this project –like last’s week important Spacebeans 1.3.0 release–. And because it is a project that will take a long time, I think I must learn to re-heat it when it goes cold.
Which may be just a consequence of how I have been doing gamedev for last few years: intense and ultra-focused on one project. Once I have started a good project, I don’t work on anything else until is finished, and considering this is low priority free time activity, it means perhaps a small-ish game needs 3 months. So I need to learn to do things differently with a potentially large project, and it is going to be hard.
Anyway, there was no “this week in gamedev” last week, but I had a few side quests and there was progress. The text wall scrolls nicely –not really “scroll” but a mid-step that looks great–, revamped controls a bit to support two buttons joystick and allow a bit of “console” control –that works very well with my menus–, and added more content to the disc –quickstart party!–.
The game still needs a name, but I’m working on it!
This week can be summed up as “menus, menus everywhere”, because that is mostly what I have been working on.
There are several challenges:
Space constraints: mode 0 resolution leaves little horizontal space, and because I wanted the play area to be reasonably large, I don’t have a lot of columns –or rows really, because the wall of text at the bottom–.
No mouse: because “emulating a mouse” is a terrible idea in a 8-bit microcomputer (see Bloodwych, for example), and using keys like i for “inventory” is a problem because the CPC can have different keyboard layouts; so I’m focusing on implementing menus handled with the cursor (or a controller).
User Interfaces are hard: independently of the system you are implementing them in!
How many inventory slots are enough? I was planning 14, but then the menu looks too dense; so currently I’m on 10 –this is per character–. I thought this wasn’t enough, but then I was playing “Bard’s Tale 2” last night and it supports only 8 slots. Is it 10 good then?
So far I think I’m happy with the results, including a very packed “stats” screen, with everything I wanted to show.
Another thing I have been working on is adding tables with weapons and armors, all from White Box version of D&D, as well as implementing the rules (e.g. Clerics are only allowed to use blunt weapons). The White Box book is very clear, but this required a lot of back and forth and, for example, realising that a Halfling can wear a plate mail armor you found in a chest in some random dungeon: of course it is the right size! But that’s basic D&D, and I have decided to implement those rules –although I’m tempted to add a house rule to require strength over 14 to use heavy items)–.
Now that I can manage inventory and equip things (weapon, armor and shield), I have everything I need to start working on the combat; which is exciting! Finally something that feels RPG.
There is something that has been bothering me, though, and I should probably work on: the text wall. Because the double buffer and reasons, long story short: it is slow. Although I improved it a couple of weeks ago, it needs a rewrite, and finding a way to make it both more versatile (should support things like “X has done Y”) and faster.
Things are looking great, let’s implement the combat!
Not much progress, but slow progress is still progress!
I’ve been mostly working on the new project: the CRPG without name (and I should come up with a name, really).
I’m glad that I started with some flashy bits first, so you can see the player moving around the world, because now I’m designing the data structures that will keep the information to model White Box –not sure if that’s the official site, but there are links to buy the book and a free PDF download–; which is the D&D ruleset I decided to implement in the game.
I mean, it is difficult and boring, and there isn’t much to show. Hopefully I won’t make any fundamental mistake!
I have also tackled another important part of the game: being able to read data from disc –using the “c” as Amstrad did–. In reality is not that hard if you use the firmware, but that requires having enabled some ROMs that will reduce considerably the amount of RAM for the game (16K for the lower ROM and a reduces a bit the memory usable between 0x8000 and 0xc000).
My approach when making CPC games is to disable the firmware and unmap all the ROMs, so I have access to all the memory. But in that case, if I wanted to use the disc, I would need to use the hardware directly. Although there are libraries for that, it would reduce compatibility with some hardware expansions like the M4 board that don’t provide full FDC emulation. As I have mentioned here, my plan is to support 64K and disc; and using a M4 is a simpler way than having an external disc unit!
So my plan was to find out if it was possible to enable the firmware “on demand”, so I had all the memory, and taking into account that when I’m using the disc –and the firmware is enabled–, the memory under 0x4000 is mapped to ROM and some memory between 0x8000 and 0xc000 will be used by AMSDOS (the kernel jump table, variables, buffers, etc).
And turns out it is possible, after some help from CPC Wiki forum, to enable back the firmware. It is tricky and it requires knowing some internal functions of the firmware that change depending on the CPC model; but considering that there won’t be any new models, it means that supporting 464, 664 and 6128 (and the plus is the same), is just enough. I wouldn’t mind adding specific support for other ROMS as well.
That is one of the good things of making software for a computer that is frozen in time. Hacks like these wouldn’t be a good idea back in the day, because a new model could break the game (kind of like happened with the ZX Spectrum floating bus trick).
After I had my disc routines working, I’m now loading the map and the tileset from disc, which opens the door for a lot of content.
After I have all the internal structures ready and I implement the “use item” function, I may work on something exciting: the combat!
I have mentioned it here a few times, that I was doing research related to a CRPG –Computer Role-Playing Game, which is how western-style classic RPGs are usually labelled–, and I finally decided to get something started.
Well, the truth is that is not the first time I started a project like that –some people may remember “Tales of Dunegon”, a false start a few years ago–, but I think this time I have something defined enough so there are chances I will end with a game.
I am not very good planing my gamedev projects. Although I do some planing, it is not very formal. Rarely I even bother to write a design document, even if sometimes I have a TODO checklist when I’m close to the end of the project, just to ensure I’m not forgetting anything.
And it is because the games I’ve been producing for the last few years are essentially simple –I have joked sometimes that they are the same game–; very mechanics focused and using the same basic components, so I tend to keep all in my head.
But an RPG is not one of those projects. It is complicated, or at least that is what I think. So I have tried to split it in sub-systems, hoping that it will make the problem more manageable (divide-and-conquer approach).
I’m not a CRPG expert, so I have decided to study some games I like to try to understand why I think they work, so I can reproduce that formula.
If you follow me on Twitter and have seen some of my posts, you probably know already that I like the Ultima series, and I’m going to borrow from there –and other games–.
I still don’t have a name, and other than the Ultima inspiration, I have decided:
I’d love to implement unofficially D&D rules, probably some of the Open Game License rules. I like the “White Box” ruleset, from the OSR movement. It is emulating rules from the original 1974 edition of D&D, with a few improvements.
I finally decided to go with the Amstrad CPC –because drawing the graphics is easier for me–, with 64K initially and targeting disc –I need to load/save data–. I may look at modern cartridge solutions like the Dandanator, or even use 128K, but initially 64K and M4 board compatible would be my preference.
I want to have the engine first, so if all goes well, I may release a first game that won’t be large. This would allow testing the engine, and later on I may iterate with other games. This is a long time commitment!
I’m making the game for myself, because I want and, hopefully, because I can!
And it should be hard, but not impossible. One subsystem at a time, and I’ll try to write some bits here as I progress in my journey.