Jump to content
Songbird

Quadromania Redux developer blog

Recommended Posts

That was a great and interesting read, thanks for taking the time to write it down!

I'm eagerly waiting for the part 2! :)

  • Like 1

Share this post


Link to post
Share on other sites

Loved this article and I did learn a couple of things actually!

More generally I like that your website is turning into something more social, where you communicate with the "fans"!

Share this post


Link to post
Share on other sites
On 5/13/2020 at 3:24 AM, Songbird said:

Raiders of the Lost ROM part 3 is now available! If you ever wanted to learn about stereo panning on the Lynx, this is your ticket.

Ever since I first tried panning I wonder if a real "surround" effect is possible. Means a sound source the virtually moves around ones head.

Share this post


Link to post
Share on other sites

Raiders of the Lost ROM part 4 is now available! I discuss how to identify and patch joypad accesses in a Lynx ROM, as well as a couple of Quadromania-specific bugs I fixed along the way.

 

Note that when I talk about patching a Lynx ROM, you will of course need to re-encrypt the ROM after the patch. Unless your ROM has an encrypted boot loader on it that does not checksum the ROM.

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites

An excellent read again! Funny to see that all the code for handling the pause button was there, just not triggered.

 

I feel this is becoming an excellent serie of articles!

Share this post


Link to post
Share on other sites
On 5/15/2020 at 9:42 AM, 42bs said:

Ever since I first tried panning I wonder if a real "surround" effect is possible. Means a sound source the virtually moves around ones head.

I don't know that you could accomplish that with panning on the Lynx. You certainly could add a depth component to the sound, though. I believe Klax does this already, where the blocks further away from you not only pan left and right, but are also quieter. Then they slowly get louder as they approach. So you could in a sense make the sound move closer or farther in addition to left or right, but I don't see how you could simulate up and down. It would be kind of neat though in a 3D game if a fireball could shoot towards the player then get quieter if it missed and kept traveling behind the player -- that would be pretty close to a surround effect.

 

On 5/15/2020 at 12:53 PM, LordKraken said:

Still super interesting, I like the amount of tech details without losing me :D

Thanks, that's my goal. :) I'm more of a brute-force hacker who looks for ways to add simple new features or fix key bugs. There are of course a lot of details I am glossing over, but I'm trying to give a higher-level view of the methodology behind the changes rather than an in-depth treatise on assembly programming.

Share this post


Link to post
Share on other sites
6 hours ago, Songbird said:

It would be kind of neat though in a 3D game if a fireball could shoot towards the player then get quieter if it missed and kept traveling behind the player -- that would be pretty close to a surround effect.

Yes. Now let's add some game play around the effect 🙂

Share this post


Link to post
Share on other sites

Once again, really cool article. I was just wondering, when you change the layout of a level, you might increase its size and then it does not fit into the original location. So you switch the level pointer to the new definition, I get that, but does that mean you know exactly at what address you have some memory free? How do you figure it out? is it like crystal clear in the asm source?

 

(This is by the way the only real annoying thing when I code in C on the lynx, I have no clue how the memory mapping is done, and the compiler - well at least newcc65 - does not give me any clue, so come a time where variables just starts to overlap and the game just randomly crashes.)

Share this post


Link to post
Share on other sites
1 hour ago, LordKraken said:

(This is by the way the only real annoying thing when I code in C on the lynx, I have no clue how the memory mapping is done, and the compiler - well at least newcc65 - does not give me any clue, so come a time where variables just starts to overlap and the game just randomly crashes.)

Memory mapping is defined (as for any compiled language) in the linker/linker-script!

Share this post


Link to post
Share on other sites

In the case of Quadromania, the levels occupy a blob of RAM but have other variables before and after them. So I had to ensure that I worked within the original start and end RAM locations. That means individual levels could grow or shrink but I couldn't go past the original end. And actually, I could have gone past the original end of level RAM by finding a new unused location in RAM and updating the level pointer. So then I'd have more of a scatter/gather list instead of a contiguous chunk of level RAM. But as it turned out, a lot of the higher levels had so many blocks I found it easy to shrink levels rather than grow them.

 

As Bastian said, you should be able to see the memory map for C code during the build process. That's a tool I've used for many years on C programming -- just haven't done any C recently! But you usually get some kind of linker output that shows your text, data, and bss. For example, I wrote Remnant for the Lynx in C with cc65 20 years ago, and here's a snipped of the "map" file output:

 

R - relative A - absolute
T - text     Z - zeropage
text-segment base address 0400
 d:\prog\lynx\newcc65d\lib/runtime.run            (0400 to 09f4 =  1525 bytes)
 ufo1.obj                                         (09f5 to 0a81 =   141 bytes)
 ufo2.obj                                         (0a82 to 0b18 =   151 bytes)
 ufo3.obj                                         (0b19 to 0bab =   147 bytes)
 ufo4.obj                                         (0bac to 0c33 =   136 bytes)
 boss1.obj                                        (0c34 to 0df8 =   453 bytes)
 sled1.obj                                        (0df9 to 0e9f =   167 bytes)
...
more stuff
...
_LoadCartBlock          962c RT _viddma                 fd92 A? 
_remlogo                2137 R? incsp7                  0464 RT 
_cos1                   a0de RB _pFirstEnemy            a450 RB 
incsp8                  0468 RT __iodir                 0090 RZ 
_cos2                   a0e0 RB _scbnext                fc10 A? 
sreggeax                0774 RT _cos3                   a0e2 RB 
_SetBuffers             8f58 RT _debris                 a108 RB 
...
etc.

So I can see all my variable locations, data structs, and function calls (such as SetBuffers()).

 

Share this post


Link to post
Share on other sites

@Fadest we need to look at that ;)

 

wow now you're  getting me pretty interested actually, as I just hit that ceiling on a project. I have to admit I never felt I was good enough in asm and low level stuff to look into that, but maybe it's time for me to that extra effort :)

Share this post


Link to post
Share on other sites

I'm not an expert in low level or compilation tools too...

 

Carl, do you remember which tool you used to get the map ?

Just tried -v option on link65 and redirect output to a text file, but I need to understand the output, not sure it is really useful apart the part in red :

Quote

[...]

NEW -> _objet_SPR 1C7, 27
-> addysp 17 0

NEW -> _ennemi_SPR 02F, 27
[...]
TEXT : 0400 (27411 bytes)
DATA : 6f13 (  819 bytes)
BSS  : 7246 (  276 bytes)
ZERO : 0080 (   44 bytes)
STACK: 775a ( 1024 bytes)

module:runtime.run                        TEXT 0400 DATA 6f13 BSS 7246 BSSZP 80
module:c37.obj                            TEXT 09ff DATA 6f3f BSS 7246 BSSZP 93

 

ennemi_SPR is an array defined like this :

char ennemi_SPR[10] = {0,IDX_BH_ENNEMI,IDX_TURRELS,0,0,0,0,0,0,0}

 

and objet_SPR

char objet_SPR[10] = {0,IDX_LIFT,IDX_TURRELS,IDX_ITEMS,0,0,0,0,0,0};

 

and should be consecutive in memory.

I do not see the relation with link65 output...

 

printobj seems to give something more interesting :

Quote

sym:_objet_SPR                       flags 2700 value : $eb00
sym:addysp                           flags 00 value : $0000
sym:_ennemi_SPR                      flags 2700 value : $e100
[...]

sym:_RENDER                          flags d00 value : $18e0
 

With endianness : $00e1 (ennemi_SPR) + 10 octets is 00EB (objet_SPR)

and RENDER is really defined at $E018 (forced in code)

 

Need to make some more test, and stop hijacking this thread :D

Share this post


Link to post
Share on other sites

My build invocations on Remnant were pretty bland:

cc65 -DCARTRIDGE main.c
xopt main.m65
ra65 main.m65
link65 -o remnant.o lynx.olb u*.obj b*.obj sled?.obj met*.obj ex*.obj cockpit?.obj remlogo.obj pw3d.obj main.obj
lynxer remnant.mak
make_lnx remnant.lyx -b0 256K

I don't recall running a special tool or tool parameter to generate the *.map file. I think I just redirected the text output to a file. But that was many years ago...

 

Share this post


Link to post
Share on other sites

Raiders of the Lost ROM part 6 is finally available! And while this closes the saga of Quadromania, the process has inspired me to hack another ROM without any original source code available -- so rest assured, more Lynxy goodness is coming down the road! But that's a story for another day... :D

 

  • Like 4

Share this post


Link to post
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.

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