Jump to content

new game: Asteroid Commander

Recommended Posts

Oh, I'll just add some functionality to these buttons, I said.  It'll just be a few chunks of code, no big deal, I said.

Hah.  Turns out I've had to create a whole bunch of interlocking systems of code.  I've had to add the idea of Events, which are pieces of code that don't get run immediately, but await some trigger condition.  Not all Events can be armed at one time, there's just too many.  Instead I need to have an Active Trigger list.  A trigger can be a countdown timer or some combination of AND and OR bitmasks for Flag bytes.  This active trigger list is checked every time the clock display updates.  If a trigger is pulled, then what follows that trigger in the list is an address in RAM of the event to take place, and that address is pushed to another list of Triggered Events, and an event handler routine later just runs all the subroutines in the Triggered Event list.

So basically the "few chunks of code" I'm needing to write is actually most of the rest of the game engine.

Even just putting text in that message window on the right raises the question: what text exactly? After writing out a bunch of messages and stuff for the newsfeed, it quickly became apparent that I was going to run out of room just for the text data.  I've had to do some sneaky compression techniques.  Some of the less-common words are spelled out, but the most common 1, 2, 3, and a few 4-character words (128 total) are represented by codes 60-BF and E0-FF, and another list of 256 (well, about 210 of these so far) words 4 or more characters long is represented by two bytes ($10 and the index of the word).  I have a vocabulary list stored in VRAM that's about 2.5kb, and 768 index bytes in low RAM pointing to these 384 words in VRAM.   My resulting compression ratio is about 3:1 right now, but I expect that to get better as I write more text and reuse these vocabulary words.

As I've been setting all of that code up, I've also been doing a few more things like touching up some sprites and the font and adding the population display on the bottom left side of the screen.  Here's what it looks like now:


Edited by Ed Minchau
  • Like 2
Link to comment
Share on other sites

3 hours ago, Snickers11001001 said:

I'm glad you're still working on this.    I don't care what happens with the X8/X16 thing/release.    I will play this game on the emulator you specify if that's all that's available.     Looks cool and its still really neat to watch someone move a project along like this in sorta real time.   

Yeah, I'm going to finish this even if emulation is the only way to play it. And if it works on x16, then I'll be able to port it to other systems too.

Link to comment
Share on other sites

  • 3 weeks later...


So this was a minor triumph.  Messages are stored as compressed text, with common words in a vocabulary represented by only one or two bytes.  This is parsed into a buffer and then divided up into lines of text.

You'll notice a couple of different fonts here.  The letters UTC after the time are on two tiles on layer 1.  All the other text is on layer 0.  The first 64 tiles on layer 0 are letters, numbers, and punctuation. 

The ellipses at the bottom of the message window is tile $80, and there's six tiles for the local area name and another six for degrees latitude, degrees North, degrees South, degrees longitude, degrees East, and degrees West, and those 12 tiles are also in that $81-8F range.  I've reserved 3 tiles for future use in that $80-8F range as well.  

That leaves tiles $40-7F for the newsfeed (currently just lorem ipsum) and $90-FF for the message window.  Each of these tiles has two characters in a tiny font. This font is only 64 characters and is stored in low RAM, and I have a subroutine that takes the left character value in X, the right character value in Y, and the tile number in A, and it creates the 8 bytes for the combined tile and pushes that to the tile data in VERA. The tile map for the newsfeed is static, except for the color information.  The tiles themselves are updated every time the newsfeed scrolls one character to the left.

For the message window, that's 10 tiles wide and 15 tiles tall.  With the scrollbar on taking up the rightmost column, that leaves 135 tiles.  But, I only have 112 tiles to work with for that window.  So, as each line is being displayed the tile map in that window is being updated line by line, padding with spaces on the right.  Even so, it sometimes runs out of tiles for the display, hence the ellipsis tile.

Clicking on the up and down arrows moves the index of the item (line number) at the top of the list to change, and the message is redrawn.  I can't click and drag on the scrollbar - yet - but I think that might be possible.

It isn't just a message window.  That same window is also used to display a message archive (sort of like an email inbox), and the main Build window (which allows selection between Life Support, Infrastructure, and Production), and then each of the Build categories will have a list that you can scroll through and select the building you want.  This window will also be used for the stock market and the local info window.  There's a lot of different things that can go in there, a lot of potential mouse click hot spots, not all of which are active at once.  So I had to set up all the code structure to do things like place a tile map in that window on the fly.

I've also added Events and Triggers.  Events are subroutines that are not executed each main loop, but are intermittent or one-time-only or delayed.  For the main loop to know when to execute those events, they need to be triggered. A trigger takes one of two forms here.  First is a Timer trigger.  This is a four byte data structure.  The first two bytes are a countdown time, decremented each time the game clock updates.  The next two bytes are either the address of an event, or if the "high byte" is zero then the "low byte" is an index to a list of events.  So, when the timer reaches FFFF, the associated event is pushed onto an event list and the trigger is removed from the timer trigger list.  Later the main program looks at the length of the event list, and if non zero executes all the events in the list, simply calling all the addresses listed.

The other type of trigger is a Flag trigger.  This is a five byte structure.  The first byte is a zero page address, the second is an AND mask, the third is an OR mask, and the last two bytes are again the event address or index.  For this type of trigger the byte is loaded from the zero page address into the accumulator and ANDed with the AND mask.  If the result is the same as the AND mask, then the zero page byte is loaded into the accumulator again and ORed with the OR mask.  If the result is the same as the OR mask, then the event is put onto the event list and the trigger removed from the flag trigger list.  This can be used to look at a single bit or all 8 bits of the byte.  Any bit values that must be 1 are set to 1 in the AND mask, any bits that must be 0 are set to 0 in the OR mask, and any bits that are Don't Care are set to 0 in the AND mask and 1 in the OR mask.  If the AND mask and the OR mask are the same, then this trigger will only fire when all 8 bits of the zero page byte are the same value as the masks.  Unlike the timer triggers, the flag triggers are all checked each time the program cycles through the main loop.

So I have three dynamic lists: two lists of triggers and a list of events called by these triggers.  The events are just subroutines, which can themselves push other triggers onto the trigger lists.  So by using the timers and flag triggers I can have events that occur some time in the future.

An example of this is something I did to the cursor.  It's a 4bpp sprite, and its default palette index is 1.  When the mouse button is pushed now, I change the palette index to 3, making it blue.  Then a flag trigger is pushed to the list, looking at the zero page value where I'm storing the value of the mouse button.  Both the AND and OR mask are zero, and the event called just changes the palette index back to 1.  So now, when you click the mouse it turns blue and when you release it it goes back to black and white.

My next step is getting the Bulldoze working and the Build secondary menus. I've also figured out a way for the user to click anywhere on the asteroid image and the asteroid will rotate and snap to that spot; I just haven't coded that part yet, as it's about 4th on the to-do list.  Bulldoze and Build shouldn't be as difficult as this window was, so my next update will a little sooner.

  • Like 1
Link to comment
Share on other sites

  • 3 weeks later...
  • 1 month later...
  • 2 weeks later...

Still not satisfied with the stars, I've kept tinkering and realized I hadn't updated my sprite and palette files.  I kept at it and now Polaris is easily identifiable when viewing from 73 degrees south in Zoom Out view, and the Big Dipper, Orion, and Sirius are easily identifiable.  There's still a small bug with stars bouncing around, but I'll get that sucker too.

I changed the way I do the closeup 3d window, and now instead of using 16 layer 1 tiles it's using a single 32x32 sprite.  This actually saved me about 5 kilobytes of VRAM, in addition to freeing up 16 layer 1 tiles.  It also means that my zoom-in overhead view can use 4bpp tiles for layer 1 without compromising the closeup 3d view window.

Looking at the remaining available memory, I should have plenty of space for everything remaining in the game: the Info button, the Stock Market button, the local area information window at the bottom, the population mood/health/numbers code, all of the Resource information, lots more sprites for things like ships in orbit or perhaps Zoom-In details, music, sound effects, and perhaps 5000 words of text for the messages and newsfeed, and various storyline events.

So next is tackling that last starfield bug, then getting rid of Lorem Ipsum and putting in the actual newsfeed, then the Zoom In view.

The more I work on this, the more I think this machine can do.  I think a DOOM port is possible.  Maybe even Halo, with a 160x120 screen and 10fps frame rate.


Orion and Sirius:



Big Dipper and Polaris:


Edited by Ed Minchau
  • Like 1
Link to comment
Share on other sites

  • 4 weeks later...

Still plugging away.  I wasn't happy with the size of the star code, and kept chipping away at it.  Now there's a single arcosine table, and all the code fits into a single bank (down from four banks) of RAM, with a kilobyte to spare.  The star data stored in VERA went from 13 kb down to 4 kb for the 1022 brightest stars (apparent magnitude 4.6 or less), and there's now recognizable constellations.

I also got started on the newsfeed, adding about 15% of the content and all the code needed to display items in a random order.  Still a ton of work left to do before this is any fun, but I'm getting there.


  • Like 4
Link to comment
Share on other sites

  • 5 weeks later...

I've got about 90% of the work done on my Zoom In code.  I also tore apart all of the biggest subroutines, the ones that take the longest time, and divided them up into chunks of around 1/200th of a second, in preparation for eventually adding ADSR envelope handlers for music, and to increase the speed of response to events such as advancing an animation.


Edited by Ed Minchau
  • Like 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Create New...

Important Information

Please review our Terms of Use