Ms Lily's Haunted Shop game releasedPrint page
There is not one but two reasons why everyone able to code should join The C64 'Cassette 50' Charity Competition! This post will try also to explain why instead of focusing on the other project (Meonlawel), I followed this path and have joined the competition with Ms Lily's Haunted Shop game.
Before I talk about the game, let's play it first if you didn't yet! It's for free, and you can play it in your web browser here.
First of all, my main motivation to participate in the competition was to support Special Effect Charity. Thanks for this initiative! Under Commocore
label, I thought about making my games partly careware but I didn't
come up with a plan yet as my projects are still on quite early stages.
The second part of the motivation was about the limitations of this competition...
Limitations
Let's talk about the lim... about the challenges! Code must fit under $1000 memory location. Also, code cannot write to memory locations above $1000 except $D000 - $DFFF area. This means that program must be up to 4kb in total. But not the whole 4k is available... Some of the memory locations below $0400 are used by BASIC and KERNAL. You can disable BASIC but what about disabling KERNAL? To disable KERNAL, changing IRQ vectors in $FFFE/$FFFF is needed but this just breaks the rules. Writing to memory above $DFFF is not allowed. As a result, KERNAL constantly overwrites some of the lower memory locations. And this makes this competition a little bit harder and challenging. In order to use more space, you have to know all the areas which might be affected by KERNAL. Only this way it's possible to fit some chunks of code here and there. At the end of this post, I am sharing the memory map of Ms Lily's Haunted Shop game code.
Overcoming limitations
This is why coding in assembly, with less than 4kb of memory
available, for ~1MHz computer from 1982 still makes sense... to me at
least. It's fun. How much can you do? And this was my first project in
assembly I've used with KERNAL being turned on. Normally, the very first
line of code in my projects is just to disable KERNAL and get the full control over the machine. So, I have to say: I've learned more
than I thought I know about Commodore 64. As I speak, I am finishing
another game for the same competition (called "Red Is Blue"), and it's a
great journey!
With the limitations, some of the things didn't fit into the game, and I needed to do some tricks in order to save bytes of memory. At the end there was not a single byte left. So, yes, it was a continuous process of optimising and trying to put more stuff into the game as long as I was able to go. This is my third competition in a row so I've got some basic experience with optimising things already. It's funny how the memory limitation got harder each competition I joined. I started with RGCD 2019 competition and the luxurious space of 16kb, this is when Swarm 16k was created. After that, in 2020 I submitted Bring back my bones 4k for Reset64 4k competition, where it took 5th place. But still, it was full 4kb of a game size I was free to use.
Let's get back to Ms Lily's Haunted Shop. I
didn't use any illegal opcodes. I'm too afraid to use any of LAX and
SBX and everything which is available on the 6510 CPU "black market".
That was my own challenge I believe to use only well-known and "legal"
opcodes which simply takes some extra bytes. But I gonna better try with some of these illegal ones in the
future.
Let me talk about some tricks. One of them was to use only a half of a sprite bank, so instead
of two enemy sprites I was able to squeeze four types of enemies! Simple, but makes the gameplay more interesting.
For the music, I created a custom music player which does only that what need to do. As it can play patterns, combining them saves some memory. I also used a limited number of notes in a lookup table. All that small tweaks save bytes... actually, they saved the whole project!
But there are more small things... Some of the tables like creating a power of two, or screen
location tables are also generated during the initialization. I was experimenting with each table to see if it's better to generate it on the fly or to use a static table. Apparently, in most of
the cases, generating these tables procedurally take less space than just including them in the program.
What didn't fit?
Well, I think everything's there what I wanted or... I am rather not
going back to talk about it :D. I should probably spend more time in
the music department and make a better song. However while testing the
game I get used to these few quickly created patterns so much that I
just left it as it is! It's a haunting tune, an earworm. I need a break
for a month to say if it was a good tune or rather a bad one.
I didn't manage to squeeze the name of the game, a simple title screen, a game over screen. Shallan's autoload code hints shared on the competition's website didn't work for me in 64tass compiler. It was just crashing. So the game code starts not from $0400 but from $0519.
Some love
I hope you've found this post interesting, or somehow useful, but in any case, I wanted to share my enthusiasm and thank to organizers for this initiative. Be sure to check other games as well! As the initial idea was to create a game in the spirit of 1983's infamous Cascade 50 compilation, I really wanted to create something which doesn't need to be fun to play at all. It could look rather awful, having basic aesthetics, sounds simplistic, and be quite frustrating perhaps. But while playing with the code I've started playing the actual game. In the end, I've put more love than initially anticipated. And I've decided to create something simple and feeling like it's finished. I hope I've met at least one of these criteria! Let me know what do you think?
Big shouts for everyone who suggested some titles for this game on Twitter. The original post is here. I didn't expect so many funny titles and word plays! Some of them are: Boot Stomp, Wander Wanda or Wanda Wander, Wandering Wanda's Wondrous Wander, Shooty McShoeFace, If the shoe fits, or... All Your Boots Are Belong To Space Wizard. Actually I've used a wizard in the story so thanks for this! As my wife
recently watched some documentary about minimalists (not the ones who
use toothbrush for everything, but just a regular ones), in a split of
second I came up with a wizard called Minimalis from Abandonia land, who
wants to conquer Fulfilia. And it was the last missing bit (or rather
byte) why this wondrous lady was wandering over this mad shop with a wand. Thanks!
Signing off!
Ms Lily's Haunted Shop memory setup
Initial PRG location before running: $0519 - $07f6
- $0002 - $0070 Variables
- $0071 - $008f Reset game procedure (relocated on init)
- $0090 - $00ff <unused> this area is affected by KERNAL
- $0100 - $011f Stack (limited to $1f on initialization)
- $0120 - $01ce Song notes
- $01cf - $01ff <unused>
- $0200 - $021f Item move mode and bounce tables
- $0220 - $0227 power2 table (generated on init)
- $0228 - $022f power2 inverted table (generated on init)
- $0230 - $026e Reset room procedure (relocated there on init)
- $026f - $02a6 <unused> but this area is dangerous (e.g. around $0277)
- $02a7 - $02ec Animate explosion code (relocated there on init as there was no more free memory to fit it under $0801)
- $02ed - $030c Clear screen procedure, displaying text "ROOM" (relocated there on init)
- $030d - $0313 <unused>
- $0314 - $0315 IRQ execution address
- $031a - $03a5 Bullet tables (this memory is usually occupied by execution addresses of KERNAL methods, but hey, we're not using them at all!)
- $03a6 - $03b1 Stage cleared text line 1 (relocated there on init)
- $03b2 - $03bd Stage cleared text line 2 (relocated there on init)
- $03be - $03bf <unused>
- $03c0 - $03ff Item dynamic sprite (copying sprite from source $0f40+ to this location for each room)
- $0519 - $07ee Init code (executed only once and overwritten after execution by drawing on this screen location)
- $07e8 - $07f4 Screen row lo positions table (generated on init)
- $0800 - $080c Screen row hi positions table (generated on init)
- $080d - $080e Item sprite colour by mana table (generated on init)
- $0801 - $0f3c Program
- $0f40 - $0fff Sprites