Jump to content
IGNORED

"Harpy's Curse" - A MetroidVania for the 7800 (Beta version now available!)


Revontuli

Recommended Posts

Beta Version Released!

 

Latest Public Betas: 

 

SaveKey/AtariVox compatible ROMs (SD Cart or A7800/HSC emulator recommended):

HarpysCurse_9_20_2023_BetaG_SaveKey.bas.a78

HarpysCurse_9_20_2023_BetaG_SaveKey.bas.bin

 

Password Only (more emulator friendly):

HarpysCurse_9_20_2023_BetaG_NoSave.bas.a78

HarpysCurse_9_20_2023_BetaG_NoSave.bas.bin

 

 

Older Build (Save system with SaveKey/AtariVox Beta):

HarpysCurse_8_18_2023.bas.a78

HarpysCurse_8_18_2023.bas.bin

 

Keep in mind this is a beta build - I do my best, but I'm sure folks will find oddities and glitches.  Please post what you find (and any other feedback) in this thread, and see later posts in this forum thread for progress and developments on the game!

 

Harpy's Curse
You are a harpy - swift of wing and vicious in nature.  Banished to a deadly labyrinth, you are tasked with defeating the four keepers of the maze - only then can you face the Great Sphinx who exiled you here.

The labyrinth contains legendary artifacts - feathers of legendary birds and beasts that might aid you.  Great power might be found here, but you truly wish for escape, and the only way out is through the machinations of the Sphinx.

 

Explore over 500 screens worth of scrolling, sprawling labyrinth filled with vicious denizens and power ups!  A password system can help save your progress if you can't finish the game in one sitting.  

image.png.7b545e5ba8ba9f3cc326eae1c08bb0c9.png image.png.1a568084fb02c3f28799a625c9e9a46a.png image.png.ec9931556d77c9a9e69b60f63564fd37.png  

 

HOW TO PLAY

Controls are configurable from a menu on the title screen - one button to jump/fly, the other to attack/swoop (or down + button if you set the controls to a 1-button joystick).  You can hold down the jump button to fly, which will be handy when exploring or lining up for an attack.

-Defeating an enemy drops their heart, which you can consume to refill lost health.
-Large hearts can be found in the labyrinth, which give you a permanent increase in maximum health.
-Keys can also be found, which unlock doors matching their color.
-Feathers of legendary beasts will bestow further abilities if found - you will get a description of what they do and how they might be used if you can collect them!

-Tablets will refill your health, provide a checkpoint if you fall to the dangers of the labyrinth, and give you a password that can bring you back even if you turn off the game.

-4 Guardians must be found and defeated before gaining access to the Sphinx, and her defeat means your freedom from the labyrinth!

 image.png.cd8fbe2d6bd7bbdb4b14058aaab1be97.png image.png.02a90694ca423e9f68afde623936de15.png image.png

 

First draft of POKEY soundtrack:

HarpysCurse_12_22_2022.bas.a78

HarpysCurse_12_22_2022.bas.bin

 

Build for Concerto + POKEY cartridge:

HarpysCurse_12_23_2022_ConcertoPokey.bas.a78

 

 

HarpysCurse_12_6_2022.bas.a78

HarpysCurse_12_6_2022.bas.bin

 

 

--------

(Original Post, preserved for historical purposes:)

(This is simply tech demo footage, a proof of concept to see if this will work on a technical level)

 

Something I've been working on as Dragon's Havoc is in the user testing phase.  It's planned to be a sort of combination between Metroid and Joust - Imagine if Samus controlled like the Ostrich Knight while navigating a large maze.  Horizontal scrolling between several sections, I'm working in bringing in enemies and different block types next.  I'm also keeping an eye on performance - I'm expanding off of the scrolling engine I made for Dragon's Havoc, but the collision detection is much more sophisticated now, the level data allows more tiles, and you are now able to move backwards.  

 

While I still have a scenario where I can fit this game in 48K, like I have with my past projects, I did some tests and I finally went mulitbank!  I started structuring the game early enough that I think I can pull it off.  Even in 48K I budgeted for at least 128 screens' worth of game (currently each 256-byte scrolling level section defines an area 8 screens long), but I'm still experimenting with how I'm organizing the level data.

 

No, I won't be moving any of the Dragon's Trilogy to multibank - they work well in 48K, they're either done or in their finishing phases, and I want them to be released in a timely manner!  Part of my reason to go into retro homebrew is to finish stuff! :)

 

It'll likely still be awhile before I even get even a demo version publicly playable, let alone released, but I want to show what I have so far since I'll certainly have questions moving forward.  For instance, I'm seeing what's needed for POKEY compatible sound as well, along with what I need to consider when making this for a cartridge - I'm tentatively going with 128kRAM, $450 for POKEY address - any pitfalls or things I need to think about with that setup?  

 

 

Edited by Revontuli
  • Like 22
  • Thanks 1
Link to comment
Share on other sites

Idk anything technical but progression is a huge part of Metroidvania. I'm sure you don't need me to tell you these things but I'm going to anyway lol. With the joust idea make early flight a first or second pickup and it's a limited resource, maybe you can get 5 presses before they glide to the ground. Then later you can get dashes or infinite flight. Of  course after playing your other games I know you don't need backseat suggestions especially for gameplay, but I think half the fun of Metroidvania is getting new and better power ups, and then learning how to break the game before your supposed to get places. I'd say if there's things where people can get lucky and bypass stuff, leave it in!  It adds to the replayability and speed run of it. Anyway I'll leave you and the other brilliant programmers to it, but given your track record I KNOW you can pull something amazing off. 

  • Like 5
  • Thanks 1
Link to comment
Share on other sites

  • 2 weeks later...

Finally got a system that can load/unload sprites from level data onto the screen.  With Dragon's Havoc I always knew where enemies would be coming from (the right edge of the screen), but here they can come from the left, right, or spawn anywhere on the screen if the player drops or flies up a section vertically.  I also need to make sure that sprites don't act persistent when they leave the screen by more than a tile or so, nor spawn incessantly if the player moves back and forth over their initial "spawn tile."  I *think* I have a system in place - at least, it's working enough to start to bring in enemy behaviors, animations, collision detection, etc.  I'm very curious how performance will go once I get all the systems (many taken and updated from Dragon's Havoc) in place.

 

HarpysCurseAgents2.thumb.png.1e1f3b55ea3637543aa3d884d8846864.png

 

If I can get one basic type of enemy in place, I think I'll have most of the "main" systems in place, at least all the ones that will be running frame-to-frame, giving a good sense of how much space and cycles I'm using.  I then plan to look and see what I can properly multibank - I've a few things penciled in, but once I have all of the main game systems in place (collision detection, level loading, enemy behavior, etc.) I can see how much of a footprint each part takes, and how well one system or another can be placed in another bank.  I already have the level loading code (with data) in a separate bank, which has been handy.  I don't have need of extra RAM just yet, but I imagine I could find use for it, especially if I go the POKEY route (or audio in general - it sounds like placing all active audio in RAM is SOP for multibank games).  

 

Each level section is 8 screens worth of scrolling wide - I'm storing each tile column in a level as a set of 5 nibbles, every 4 bits defining 1 of 16 possible sets of 2 blocks.  That's enough for a few solid block types, a background tile or two, a danger tile like, say, spikes, and potentially one or two special block types like water.  I think I'll try and be clever and use every 6th nibble to store part of the enemy data for a section - The enemy density won't be that high, so I might be able to fit enough data to have a full level section with both blocks and enemies in a 256-byte array.  I've half a mind to add another array that could expand the possible tile sets from 16 possibilities to 32 or 64, especially as I fully embrace multibanking and extra RAM, but having a byte-per-tile would be overkill, and I need to keep an eye on my CPU cycles as I generate each new column as I scroll the screen.

  • Like 4
Link to comment
Share on other sites

Wall of text incoming - taken from my dev diary:

 

Getting used to bank switching - It's certainly easier to start a project with separate banks in mind than to try and switch halfway through!  

 

Here's a current breakdown of the ROM: 
   9922 bytes of ROM space left in bank 1. <- Bulk of the initialization and game logic
   15174 bytes of ROM space left in bank 2. <- Level loading subroutine and current location of level data (which should move to another bank or banks later)
   0 bytes of ROM space left in the main area of bank 3. <- 2 Graphic blocks...
             3460 bytes of ROM space left in DMA hole 0. <- ...and the "draw code" to actually plot the screen data and player/enemy/bullet/object sprites before double buffer flipping.
             4096 bytes of ROM space left in DMA hole 1.
   16383 bytes of ROM space left in the main area of bank 4.
   16383 bytes of ROM space left in the main area of bank 5.
   16383 bytes of ROM space left in the main area of bank 6.
   16383 bytes of ROM space left in the main area of bank 7.
   7861 bytes of ROM space left in the main area of bank 8. <- The shared block. I currently have 1 graphical block (so I'll have access to 3 when shared with bank 3), sound info, Pokey stuff and other .asm modules
   custom pokeysound assembly:  743  bytes
     $18e0 to $1fff used as zone memory, allowing 14 display objects per zone.
     441 bytes left in the 7800basic reserved area.

 

A 16k bank can theoretically give me 64 "levels" with 8 scrollable screens each with the way I've structured things at the moment, so a cool 512 screens. Even if I add some header data to expand the number of types of tiles I can use, I think that's double the size of the labyrinth in "Legacy of the Wizard" in terms of screens, so I think I'll have a fun amount of space to play with if devote 1 or 2 banks to level data. 

 

I'll see how much space in bank 1 once I implement a set of enemy behaviors, but ~10k I still have in bank 1 is a fair amount to work with to implement the logic.  Too many instructions and I might hit performance issues anyway.  I'm wary of gosub, particularly to other banks, since that was pretty costly on the 2600 (you usually want to find a way to make it a goto), but I might have more use of it here.  It works great with the level loading, especially since I can get away with that taking an extra frame or two as I fade in the new level from black.

 

I plan on including bosses, and that's where I might really appreciate the extra banks - I could probably do a boss or two (plus palette shifted versions :) ) if I stuck to 48k, but this gives me a lot more freedom to think about what I could do.  In "Dragon's Havoc" I had a lot of code for the bosses that looked copypasted from the enemy behaviors, but was *just* different enough that I couldn't really combine the two in an elegant way, so putting boss behaviors in a separate bank might actually avoid the usual frustration of code duplication between banks.  

 

I'm bringing in the Pokey engine for music, and the hiscore module - not for scoring, but to allow the possibility of saving your game progress.  I also have a plan for a password system for those lacking a Savekey or AtariVox.  Most of these modules need to be in the shared bank, so I need to be careful.  Thankfully I managed to structure a lot of the graphics and logic so they don't need to be in the shared bank as well, but I'll see how crowded bank 8 will get when I bring in proper music and sfx.

 

On that last matter, I might ask for help from folks in the know about how to manage audio in RAM - I haven't even touched the extra RAM bank in the 128kRAM setup yet, but I have a feeling it will come in handy!

Edited by Revontuli
  • Like 4
Link to comment
Share on other sites

HarpysCurseTiles.thumb.png.f2f561584891182832361e81193a56f5.png

 

Tile types beyond solid and background!  I added in spikes and water - I'm hoping I can get the behaviors for both without adding *too* many more cycles to the block collision response.  The details still need a little work, but you can swim and get hurt on the spikes (usually - a few more tests...)  I want to play with the exact dynamics, but this is a good test - even graphically being able to add more than "solid or blank" to the level is nice.  I also made some optimizations to how I was generating the tile columns - at the very least it's hitting the array a little less, and the array itself is a little smaller.  Part of this is due to the decision to have every tile be 16x16 pixels from the graphics block - this could lead to a tile or two being redundant, or not being able to re-use "half" tiles, but even in Dragon's Havoc I only used that flexibility for 2 tiles or so in the tiled stages, and it will greatly simplify bookkeeping here.  I have a better idea of how many types of tiles I need and can use, and where I can fit them into the multi-bank structure.

 

ROM breakdown to date: 

 

   9594 bytes of ROM space left in the main area of bank 1.
   15174 bytes of ROM space left in the main area of bank 2.
   0 bytes of ROM space left in the main area of bank 3.
             3242 bytes of ROM space left in DMA hole 0.
             4096 bytes of ROM space left in DMA hole 1.
   16383 bytes of ROM space left in the main area of bank 4.
   16383 bytes of ROM space left in the main area of bank 5.
   16383 bytes of ROM space left in the main area of bank 6.
   16383 bytes of ROM space left in the main area of bank 7.
   7861 bytes of ROM space left in the main area of bank 8.
   custom pokeysound assembly:  743  bytes
     $18e0 to $1fff used as zone memory, allowing 14 display objects per zone.
     513 bytes left in the 7800basic reserved area.

 

HarpysCurseTiles2.thumb.png.9da3054ede05169d107d5bf6a3a0477c.png

 

  • Like 5
Link to comment
Share on other sites

1 hour ago, BydoEmpire said:

. It's nice to see what other games look like as a sanity check.

It's my first 7800 game with bank switching, too, and I still have a lot to figure out, but it's good to compare notes!  I'm glad my notes are helping, although I'm also posting to see if anyone points out any glaring error or inefficiency :)

 

Having one bank be the "graphics and final plots/drawing" seems to make sense, while having other banks handle the logic.  I haven't taken advantage of the RAM bank yet, but it feels like you can store a lot the game state and logic there when you do the final screen drawing.  Having a "gosub" bank for operations that aren't as time critical (like level loading - if it takes a few frames to load a level that's usually not a big deal) also seems to make sense.  Code re-use at some point is probably inevitable - I want some more ornate bosses, for instance, and that will likely need its own bank - but this seems like a good way to leverage the bank space while avoiding too much redundancy.

  • Like 2
Link to comment
Share on other sites

  • 2 weeks later...

I have systems in place to create different types of enemies and non-enemy objects, although how they'll ultimately behave is now more a matter of game design than software design - more art than science, really.  That takes a while, in the form of sketching, prototyping, and daydreaming, but I still have plenty of straightforward coding stuff to do.  

 

I've currently designated bank 7 as the "Menu" bank, where the title screen, control options, ending sequence, and pretty much anything involving text will go.  I could give the bank its own graphics block - not absolutely necessary as I currently have the text in the shared bank, but the temptation to add a ton of graphical flourishes is there :)  I'll see how much space I have left once I get the necessary stuff in.

 

I'm adding the option to change your controller setup - whether button 1 or 2 is the jump or attack button, as well as the option for a single button controller.  

 

The 1 button setup uses the button to jump and [down + button] to attack.  Since your main attack is a fast downward swoop, I'm hoping using the button for the two actions won't clash much in practice for folks.  I actually prefer it when playing on physical hardware.  

 

Current Bank ROM usage (with tentative plans for currently unused banks:

 

   8780 bytes of ROM space left in the main area of bank 1. <-Main Game Logic
   14595 bytes of ROM space left in the main area of bank 2. <-Level Loading and Level Data
   0 bytes of ROM space left in the main area of bank 3.   <-Main Game "Draw" Section + Level and Enemy Graphics
             3098 bytes of ROM space left in DMA hole 0.   <-Plotmaps, PlotSprites, etc. for main game loop
             4096 bytes of ROM space left in DMA hole 1.
   16383 bytes of ROM space left in the main area of bank 4.<- More level data?
   16383 bytes of ROM space left in the main area of bank 5.<- Boss graphics and behaviors?
   16383 bytes of ROM space left in the main area of bank 6.<- Music and sound data?
   15128 bytes of ROM space left in the main area of bank 7. <-Menus, Title Screen, Text screens
   7841 bytes of ROM space left in the main area of bank 8. <-Shared Bank (mostly sound + shared graphic block at this point)

 

Very little code duplication in separate banks at this point - I'll likely need to re-use the number and text graphics, since you can only use one graphics block at a time for charsets.  The bosses might need some copypasted code for the final draw pass (again, mainly due to wanting a specific graphics block for them), and I'll likely need to copy the level data->RAM routine to bank 4, but it's a simple loop that takes very little space, worth it to get another 15ish kilobytes of level content.  I'll see how much more space I'll have in bank 1 as I add more enemy AI, item behaviors, and other elements.  I've no doubt I can burn through ~9k, but it doesn't feel claustrophobic yet, and I still have other banks open as of now.

 

If I do use a specific non-shared bank for audio data, I'll want some help on how to loading such into RAM, especially if I commit to using POKEY-compatible audio.  I haven't actually touched the extra RAM bank yet, and I have a possible design where I might not need to, but I figure that loading POKEY tracks would be the "killer app" that would justify it. 

 

Thanks for everyone's help - this is incredibly fun, but really only possible due to folks sharing their knowledge and tools!  I hope posting highlights from my dev diary helps folks a little bit in turn.

Edited by Revontuli
  • Like 3
Link to comment
Share on other sites

On 3/22/2022 at 4:41 AM, Revontuli said:

I haven't taken advantage of the RAM bank yet,

For games like EXO and Keystone Kapers, I used the extra RAM for a bunch of things.

 

  • Extra variables (because I'm mostly lazy! but does come in useful for setting all the colour values to variables and setting them at the start for PAL or NTSC)
  • Extra display memory so you can get a few more things on screen without issues.(You will still run into an overall limit but this pushes the wall back a bit).
  • Playing Pokey tunes from RAM so they can sit in their own bank, copy to RAM when needed. (EXO had 14 or so tunes so I added an unlockable pokey player)
  • Screen mapping

 

Something else I found to be a good technique (suggested by Matt) is when you transition from a bank to another bank and change the graphics, in between that action, call a bit of code that just blanks the palette to $00. That way you can avoid ghosting / artifacts when switching (not sure of the best way to describe it). Then reset your palette to what you need after you have cleared the screen etc.

 

  • Like 4
  • Thanks 1
Link to comment
Share on other sites

8 hours ago, Muddyfunster said:

I used the extra RAM for a bunch of things.

 

  • Extra variables (because I'm mostly lazy! but does come in useful for setting all the colour values to variables and setting them at the start for PAL or NTSC)
  • Extra display memory so you can get a few more things on screen without issues.(You will still run into an overall limit but this pushes the wall back a bit).
  • Playing Pokey tunes from RAM so they can sit in their own bank, copy to RAM when needed. (EXO had 14 or so tunes so I added an unlockable pokey player)
  • Screen mapping

Excellent advice - and good to hear.  There's a fair amount of technical information around, but finding good design practices can be harder to find (it's often in the forums, but can be trickier to search for than specific tech terms).  Having the screen "black out" when switching between banks and blocks is good to know, especially as I bring in different menu screens.

 

Atari 2600 development has taught me to be stingy with variables, and the 7800 already felt freeing before the extra bank of RAM - having an additional 16K can sound decadent if you're used to fitting game logic into 128 bytes!

 

Of course, one can always find uses for more RAM - my priorities would be for the Pokey tunes, as you mentioned, followed by some extra display memory (mainly to give the MARIA some breathing room, the graphics seem to be under control, but it feels like I'm on the knife's edge right now).  

 

My other concern is how much a RAM bank will complicate making a physical cartridge as well as emulation - it seems like the some platforms want (at least) an adjustment to the header file.  The most feasible method for adding Pokey compatibility is of course the big question for a physical cart, but moving up from 48K to larger layouts complicates production regardless.

  • Like 1
Link to comment
Share on other sites

I have a few questions - based on some bug hunting I've done this last week - hopefully this is coherent:

 

-For 7800Basic, does all "const" care about is when it's called/defined? And it just does a string-to-number replacement at compile time?  So you want to call it earlier in the file?  And it doesn't care about banks?  I've had some issues where it compiles and works fine on emulator, but creates strange behavior on the Concerto - putting all the "const"s at the start of the file fixed the issue.  Oddly, it was a case where the emulator version probably should *not* have worked, if things are as I understand them.

 

-I have some graphic block/bankswitching behavior that *seems* to work, but I might be getting away with something I shouldn't:

 

   *I have the bulk of my game logic in a bank with no graphics block (besides the shared one in bank 8).  I use the double buffer, and use a characterset, draw and "flip" the buffer in a separate, devoted bank.  This seems to work fine, on emulation and on the Concerto, but I wanted to make sure this is proper behavior.  I'd rather know now than find out it won't work when I'm burning the final EPROMs!

   *The way I have things set up now is nice - the background gets its own full graphic block (the characterset I use for a in-game frame), as do the enemies/objects, and I can fit the logic in its own block without having to make room for the graphics there.  With the "final draw" bank I have access to 3 graphics blocks (1 shared, 2 in-bank, although of course only 1 character set at a time),  the game logic totally different bank.  I just want to make sure I can get away with this...

   *Oddly, the only graphical glitch occurs when I load in a new level from *another* bank, which also has no graphical block (or draw calls) defined in it.  Honestly, this is kind of expected behavior, and I get around the issue just fine for the moment (going to black and fading in, a practice which I've had recommended to me).  I'm more worried that this *isn't* happening normally, even if it is, at the moment, to my benefit...

  *I guess my main question would be: why would the graphics glitch in "load level" bank, and not the "game logic" bank ?  My going theory is that loading a new level is a longer process that might last more than a "frame" worth of time, and glitch the hidden part of the double buffer before I flip it.  The bank layout as I have it below:

   
   8723 bytes of ROM space left in the main area of bank 1. <- Game Logic here
   14608 bytes of ROM space left in the main area of bank 2. <-Level Loading here
   0 bytes of ROM space left in the main area of bank 3.  <-Final Graphics Drawing (and doublebuffer flipping) here
             3082 bytes of ROM space left in DMA hole 0.  <-DMA hole created by level background character set
             4096 bytes of ROM space left in DMA hole 1.  <-DMA hole created by enemy graphics
   16383 bytes of ROM space left in the main area of bank 4.
   16383 bytes of ROM space left in the main area of bank 5.
   16383 bytes of ROM space left in the main area of bank 6.
   14253 bytes of ROM space left in the main area of bank 7.  <- Title Screen and Menus
   7841 bytes of ROM space left in the main area of bank 8. <-Shared bank with its own graphics block (player sprites, title screen/menu font - I *don't* use text in the game proper, only in menus at the moment)

 

TL;DR - Given the bank layout above, is it ok to run the game logic in bank 1, goto bank 3, and draw everything, flip the double buffer, and then goto bank 1 for the next frame to start the logic again?  Or will I ultimately glitch the graphics?  Again, seems fine on the Concerto...

 

Thanks for everyone's comments and help so far - I know my messages get pretty long and complicated, but I generally only ask for help when I'm deep in a hole, or have a complicated question :P

 

  • Like 1
Link to comment
Share on other sites

On 4/5/2022 at 1:15 AM, Revontuli said:

I have a few questions - based on some bug hunting I've done this last week - hopefully this is coherent:

 

-For 7800Basic, does all "const" care about is when it's called/defined? And it just does a string-to-number replacement at compile time?  So you want to call it earlier in the file?  And it doesn't care about banks?  I've had some issues where it compiles and works fine on emulator, but creates strange behavior on the Concerto - putting all the "const"s at the start of the file fixed the issue.  Oddly, it was a case where the emulator version probably should *not* have worked, if things are as I understand them.

the const statement needs to happen before you use it. The constant name looks like a plain old variable/symbol too, so before 7800basic generates assembly code, it checks it's list of constants to see what assembly it should generate. If the const statement hasn't happened yet, the assembly will be geared toward a variable instead of a constant. Ideally 7800basic would throw an error in this case, but for architecture reasons it's not really practical.

 

On your bankswitching question, you're almost certainly correct that your game logic bank time is brief enough that it's not impacting the display. I don't think anyone can tell you that it's fine to do that, as you might need to add more logic later and it will put you over the edge. Or possibly there's a sequence of conditions that may put you over the edge. There aren't any guarantees here, unless you put required graphics in that same bank. I'm not telling you that you need to do that, just that you'll have to watch the situation closely as code gets updated if you don't.

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

6 hours ago, RevEng said:

On your bankswitching question, you're almost certainly correct that your game logic bank time is brief enough that it's not impacting the display. I don't think anyone can tell you that it's fine to do that, as you might need to add more logic later and it will put you over the edge.

Thank you - I suspected this was the case.  I'll keep that in mind as I add to the game logic - luckily there's some space on the shared and "graphical" banks, and I might have some alternative ways to reorganize the graphics if space gets tight.  It seems to work fine on the Concerto, so I'm hoping if the graphics work there they'll work on a cart.

 

Plus, I still haven't tapped the extra bank of RAM - I know it's *possible* to put graphical data there, has anyone posted or shared methods of doing so?  I imagine some careful inline assembly would be needed for a 7800Basic project.  

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

7 hours ago, Revontuli said:

Thank you - I suspected this was the case.  I'll keep that in mind as I add to the game logic - luckily there's some space on the shared and "graphical" banks, and I might have some alternative ways to reorganize the graphics if space gets tight.  It seems to work fine on the Concerto, so I'm hoping if the graphics work there they'll work on a cart.

 

Plus, I still haven't tapped the extra bank of RAM - I know it's *possible* to put graphical data there, has anyone posted or shared methods of doing so?  I imagine some careful inline assembly would be needed for a 7800Basic project.  

Since we're talking about relative timing to the video signal, and the signal and code will get synced up in the 7800basic initialisation, testing with Concerto should provide the same results as an eprom cart.

 

You can throw graphics into cart memory at 4000, with a caveat. The "holey dma" doesn't extend that far down, which means this memory area isn't suitable for sprite graphics where the sprite might be at an arbitrary Y. You can stick graphics for charactersets, banners, and any zone-aligned sprites in cart memory.

 

As for the question of "how", it definitely uses some assembly. When we mess with 7800 DL memory, we call that "under the hood". To extend the analogy, I'd say in terms of complexity this one is more like "opening up the engine block". In broad strokes, you need to include/incbin a file that has your graphics data somewhere in your rom, and use memcpy to copy it to the cart ram. Then, to use the 7800basic graphics commands, you need to setup a bunch of assembly constants that define various attributes for the graphics data. (including the location of the graphics, which should be cart ram). The "easiest" way to get the needed graphics data and constants is to compile a temporary program that brings in the graphics with incgraphic, and pry the needed stuff out of the temp program generated files.

 

If you're still keen to do it, after hearing the limitations, I can go into more detail. But it's all a bit hairy.

 

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

7 hours ago, RevEng said:

Since we're talking about relative timing to the video signal, and the signal and code will get synced up in the 7800basic initialisation, testing with Concerto should provide the same results as an eprom cart.

Good to know - I'll likely be testing on a Dragonfly soon as well, as I try to see if I can get Pokey-compatible sound in.

 

7 hours ago, RevEng said:

You can throw graphics into cart memory at 4000, with a caveat. The "holey dma" doesn't extend that far down, which means this memory area isn't suitable for sprite graphics where the sprite might be at an arbitrary Y. You can stick graphics for charactersets, banners, and any zone-aligned sprites in cart memory.

My scrolling system basically involves cutting a screen-sized character map in two and shifting them a little bit on the x, but since there's no y movement, that might actually work.  I still need to draw the player, enemies, and objects on top, though, and those can be anywhere.  

 

7 hours ago, RevEng said:

If you're still keen to do it, after hearing the limitations, I can go into more detail. But it's all a bit hairy.

Thank you for the info - while does sound like something I could actually take advantage of, I'm going to implement some other things first and see how well everything else fits together.  I might ask later, but for now I think I can work with the ROM-based graphic blocks.  I'm juggling how to load and process enemies and other objects, so I'm at my own limits of hairiness at the moment :)

 

I had originally thought the double buffer would protect me from multi-bank graphic block switching, and it kind of does, but one still needs to be careful!

 

I'm re-organizing how I'm laying out my graphics blocks and bank a little, now that I realize I was butting up against some CPU/MARIA timing limits.  Honestly, the new layout makes more sense - The background tiles are in the shared bank, not because they're used everywhere, but because when they are used, I'll be jumping around the most banks and likely spending the most time-per-frame there.  

 

Before, I instinctively put the text in the shared graphics block.  The thing is, it that takes up a ton of space, I can really only have one characterset active at a time, and I really only need it for menus and dialogue-specific screens, so it can go in the "Menu" bank.  I still have the numbers in the background tile graphics block, but honestly I could probably make an icon-based UI during gameplay that doesn't even use that.  I'm basically going from 3 graphics blocks at once (one of which I wasn't really using) to 2 blocks - The biggest real change is that I'll have the player graphics share space with the enemy/object graphics, which won't be *that* big of a hit in terms of space.  And if I feel risky, I might see if I can get away with putting the enemy graphics block back in bank 3, since I was still getting away with it there.

 

Thank you again for your help - I know these are lengthy posts, but I think it's good to document the design process along with the tech.  Multi-bank design is as much an art as a science!

 

  • Like 2
Link to comment
Share on other sites

It's been awhile since I've posted a screenshot - more prototyping and stress-testing, really:

 

HarpysCurseEnemies.thumb.png.36058a756e45cc565dcf29ce50101dbb.png

 

You'll notice a life bar, collected key, 4 enemies and 2 shots onscreen.  I've been modifying my level editor script from Dragon's Havoc - I can "paint" levels as a bitmap, which includes placing enemies and items, although I need to be a little careful how and where I put them, and then output it to a data array to copypaste into 7800basic.  A lot of arrays and indices, often referring to other indices and arrays ?

 

The collected key can open doors, the enemies can have different behaviors and appearances, your health meter diminishes when touching things you shouldn't, leading to a game over when its reduced to zero - all things that sound simple but are crucial to design so that all the components play nice together.

 

The immediate next step is to organize my palettes - they fade nicely, and I can define each level's color scheme, but I need to extend that to the enemies, items, and UI elements.  It's an easy step to put off, but it's a good thing to have taken care of when you're constantly testing other features.

 

Mid-term is to get 2 types of enemies, 2 types of keys/items and a dummy boss working.  If I can get 2 of something working, it's usually easy to get a third, fourth and so on.  Something of a "vertical slice" to make sure each thing is working before going forward and making the full game in earnest.  

 

Once I have a gameplay "vertical slice," I might actually get around to playing with POKEY audio - I have a few ideas, but I want to see how the rest of the game's "skeleton" fits together first...

 

Thanks again for everyone's help and advice - I imagine I'll be asking some other questions as I test these game data and mechanic systems on an expanded 7800 ROM space!

  • Like 5
Link to comment
Share on other sites

Getting the general foundation worked out for the whole game:

7800basic compilation complete.
User-defined 7800.asm found in current directory
   stack allowance: 6 nested subroutines.
   the canary is situated at: $1ea
   8012 bytes of ROM space left in the main area of bank 1. <- Main Game Logic
   11153 bytes of ROM space left in the main area of bank 2. <-Level Loading/Data
   6806 bytes of ROM space left in the main area of bank 3. <-Drawing Graphics
             4096 bytes of ROM space left in DMA hole 0.
   6364 bytes of ROM space left in the main area of bank 4. <-Drawing for Bosses
             4096 bytes of ROM space left in DMA hole 0.
   16383 bytes of ROM space left in the main area of bank 5.<- (more level data?)
   16383 bytes of ROM space left in the main area of bank 6.<- (music/sound?)
   5586 bytes of ROM space left in the main area of bank 7. <-Menus
             4096 bytes of ROM space left in DMA hole 0.
   7656 bytes of ROM space left in the main area of bank 8. <-Shared Bank, mostly graphics and sound currently
   custom pokeysound assembly:  743  bytes
     $18e0 to $1fff used as zone memory, allowing 14 display objects per zone.
     513 bytes left in the 7800basic reserved area.


Getting close to a minimal prototype - the equivalent of putting every item, key, and boss next to each other to make sure the systems all work together.  I mean to have 4 keys, each of which opens 1 kind of door.  Teleporters are a possible encounter - able to send you to any location in the game.  On top of that, I have 4 life-ups (think Heart Containers in Zelda or Energy Tanks in Metroid) to hide in the labyrinth as well.  I have 2 dummy bosses working, and I mean to up that to 5 (4 regular bosses and 1 final boss), which should hopefully be pretty straightforward now that I have 2 working.  As with a lot of programming, making the 2nd element is the hardest - the 3rd and 4th are usually much easier.  

 

A lot of this week has been working on boring stuff that folks would immediately notice if it wasn't working.  I need to keep track of what a player has collected, for instance, and make sure I "remember" that an item is present or gone as I load and unload different level sections.  Same for bosses, and same for similar types of little things for enemy loading/unloading in a scrolling world.  It's all stuff I'll likely be wrestling with throughout development, but the basic stuff is mostly in now.  Being able to backtrack through the entire game makes things a lot more complicated than a simple "scroll forward" game!

 

Oddly enough, while I mentioned playing with sound, I think the next steps I'm going to tackle are to get a space to have an ending sequence, and then a password/save system.  I finally have a complicated enough game state that I can build and test that!

 

Screenshots wouldn't be much to look at - if this were a house, it'd still be scaffolding and drywall, but the foundation is poured and the plumbing is nearly done.  *Then* I can start bringing in the furniture and picking the paint colors, so to speak.  I'm trying to get all the general stuff in before I work on unique elements like boss behaviors.

I still have 2 banks I haven't touched, nor have I used any of the expanded RAM yet.  One of the banks will almost certainly be for more level data, and the other bank will likely hold sound and music.

  • Like 4
Link to comment
Share on other sites

A few updates, and another screenshot...

 

I expanded the level data to fit into bank 5 as well as bank 2 - I don't need it *yet*, but it will be easier to remember to do now, and make sure the branching/loading method I'm using works.

 

I can designate a boss as a "final" one, and defeating it will go to an ending state/sequence, so you can "win" the game now, such as it currently is :)

 

Started the password system, for those without a SaveKey or AtariVox (which I'm also planning to support) - I'm still working on the proper graphics and colors, but the functionality is largely there (although I'm still working on some encryption methods):

 

HarpysCursePassword.thumb.png.44861b06f9dc482d51685e0e0019870d.png

 

I've been logging the compiler outputs - mainly to see how the project progresses as well as seeing how "heavy" each added feature is.  The password screen/system weighs in around 1 kilobyte at the moment - not too bad, and within my current ROM "budget" I have for the bank devoted to menus, but text and menu systems can devour ROM space pretty quickly if you're not careful! 

  • Like 5
Link to comment
Share on other sites

Y'all called it - I took a page from Castlevania's various password systems, although those got surprisingly complicated.  The icons grids from Bloodlines and 3 are a nice way to encode a bunch of booleans.  I didn't want to program an alphabetical input system, and I doubt anyone wanted to use one :)

 

Finalizing the level format - although in terms of appearance it's still all largely temp, test, and older sprite art - I'm getting to the actual "art" phase soon.  The *types* of blocks are in, though, so I can actually think about what they'll look like.  I'm looking forward to toying with how spikes, water, columns, and statues will look in various parts of the maze...

 

HarpysCurseStatues.thumb.png.51ef872a33b20d37ffaa912ae6ed72fe.png

 

 

 

Current compiler output:


7800basic compilation complete.
User-defined 7800.asm found in current directory
   stack allowance: 6 nested subroutines.
   the canary is situated at: $1ea
   6402 bytes of ROM space left in the main area of bank 1. <- (Main game logic)
   12977 bytes of ROM space left in the main area of bank 2. <- (Level data)
   6450 bytes of ROM space left in the main area of bank 3. <- (Normal game drawing)
             4096 bytes of ROM space left in DMA hole 0.
   6287 bytes of ROM space left in the main area of bank 4. <- (Boss drawing)
             4096 bytes of ROM space left in DMA hole 0.
   13861 bytes of ROM space left in the main area of bank 5. <- (More level data)
   16383 bytes of ROM space left in the main area of bank 6. <-(Tentatively reserved for sound)
   2393 bytes of ROM space left in the main area of bank 7. <-(Menus and other Text screens)
             4096 bytes of ROM space left in DMA hole 0.
   7623 bytes of ROM space left in the main area of bank 8. <-(Shared bank, .asm modules, current sfx, player and level background graphics)
   custom pokeysound assembly:  743  bytes
     $18e0 to $1fff used as zone memory, allowing 14 display objects per zone.
     513 bytes left in the 7800basic reserved area.

 

A busy week trying to finalize the rest of the game systems.  Adding a feature is an O(n^2) problem, as you have to reconcile any new feature with every one you've added previously, trying to fix any bugs you've discovered or introduced...

 

Today was coding more enemy behaviors - I think that those will be the last major CPU processes in the main game loop - if it runs OK with all this in, I'll feel much better playing with the data.  I've been having fun with it, though - I'm able to combine different movement patterns with other qualities (does the enemy shoot?  is it affected by gravity?) so that they can be a variety of types of enemy behavior for the player to encounter.  

 

The maze will have a few things to look for - while I do have explicit keys and locks, I also have a few powerups. I'm not making the powerups required, for the most part, but they'll be *very* nice to have.  Collecting one of them will give a screen telling you what it does and how to use it - Of course, part of me was tempted to make this game as cryptic as Legacy of the Wizard or Goonies 2, but I think folks expect a little more fairness (and explanation) nowadays. 

 

I've roughly budgeted how big the game will be in terms of levels - My next step will be adding in a "blank" data to make sure it all fits and loads in ROM.  I mentioned my estimate above - I think between 2 banks I can get 64 "sections" - each section being a horizontal scrolling area 8 screens long - so 512 screens total, each screen being 10x10 tiles.  I could probably make even more, but I want to see how much space the other banks use once I get a better handle on how much more space other systems (particularly sound) will need.  And I should see how big this much level data feels as I start planning out where to place powerups, keys, and bosses.

 

The password system is working, although I'm not encrypting it yet, as it's currently a nice debug system to cheat progress at this point.  I've a plan to use SaveKey/AtariVox as well, which will hopefully be straightforward since I'm not using any of the data to save a high score on this game.  It still requires testing on physical hardware, which I have, but iterating and testing on such hardware takes that much longer, so I've been putting it off...

 

...oddly, the first ROM bank I'm starting to feel the "crunch" on is the one I allocated for menus.  Text and proper menu/UI behavior takes up a ton of space!  I have the basics in, except for the Save/Load screen.  I'm pretty sure I'll be able to fit the menus in on a functional level, my main worry is how much will be left over for fun stuff like the ending, pretty title graphics, etc. 

 

Sounds and saves notwithstanding, I'm actually shifting gears into content.  As mentioned above, I'm starting level design proper (not just formations to test stuff), as well as starting to doodle some sprites and pixel art again.  It's tricky, though - you an *finish* a feature, but you never complete art and design, you can only to get to a point where you can say "eh, good enough."

 

I may ask about this is a more focused post, but while performance *seems* okay on both BupSystem and the Concerto, A7800 sometimes gives a graphical "stutter" - It doesn't *seem* to be related to how busy the game is (i.e. performance as such, it happens at intervals unrelated to, say, how many enemies are on the screen), and it might be something similar to what I ran into with Dragon's Havoc, where a slight mismatch in game and display framerates "catches up" at regular intervals.  As I said, it still seems to run OK on the Concerto, but I'll be testing more on A7800 (and the Dragonfly, once I get the power supply figured out) as I try my hand on including POKEY sound.  
 

  • Like 6
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.
Note: Your post will require moderator approval before it will be visible.

Guest
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.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...