Updates:

Fans are welcome!

Modifiying corridors

Started by optomon, March 12, 2010, 03:55:20 PM

Previous topic - Next topic

optomon

This topic for discussion of corridor level modification.

The pointer table at 0x10024 is where to look first. The first two pointers (6D 82, ED 81) are data for the game's two nonplayable flight sequences (entering/exiting a corridor, and the escape from Naju just before it explodes). The following are for the games for the games 23 corridors, starting with the beginning stage (45 80), then followed by corridor 1, 2, 3, etc. all the way up to 21 and the final stage (11 85). Each corridor level data block will start with the bytes "00 00 04". From there it gets complex, and I'll discuss it more in detail here as time moves along.

tummai

I'll do a brain dump of my notes on the corridors too:

Metatiles and Metarows

The game organizes background tiles into 16x16 metatiles.  It then constructs "metarows" out of these metatiles.  There are 16 metatiles in one metarow and one metarow covers the whole width of the screen.  Metatile definitions are located in bank 5.  Metatile definitions are 5 bytes each, composed of the tile ids for the top left, top right, bottom left and bottom right tiles (in that order) plus a palette index.  Metatile definitions for the Space Platform tileset start at 0x17178.

Corridor level data

As optomon said, the corridor pointers are at 0x10024.  Corridor level data itself is composed of opcodes.  There are 10 opcodes in total, numbered 01-09.  Each opcode is followed by 0 or more arguments, plus a 16-bit "timer" value.  I put "timer" in quotes because the corridor engine is actually "timed" by number of metarows drawn rather than an actual time measurement.  The timer value at the end of an opcode tells the engine how many metarows to wait before running the next opcode.  More on opcodes below.

Metarow Construction

The whole timing system for the corridors is based on metarows.  One metarow drawn is cosidered one tick of the timer.  Metarows are constructed in a complicated way.

Metarow Base

First, metarows have a default background, which I will call the "metarow base".  The metarow base is set with opcode 01 (see Opcodes below).  The metarow base is a full metarow (ie, 16 metatiles) wide, but it may be more than one metarow tall.  For example, in the space platform tileset, there are two metarow bases:





The first one consists of a single metarow, the second consists of two.  In the latter case, when the corridor engine renders the metarow base, it will alternate between the two metarows available.

Metarow Patterns

There can be up to 8 timed "metarow patterns" that are drawn on top of the metarow base.  The patterns are set with opcode 06 (see Opcodes below).  Metarow patterns can be less than 16 metatiles wide, and can be more than one metarow high.  They can also have transparent areas (ie, parts where the metarow base shows through).  Here are two examples of patterns for the space platform tileset (white = transparent):





These two patterns are drawn on top of the metarow base to produce a scene like this (palettes will be slightly off):



In this scene, the first pattern is repeated every time, while the second pattern has a longer interval before it is repeated.  As mentioned above, each pattern is on its own timer, and again timing is based on metarows drawn.  Up to 8 patterns can be running at once, which allows a lot of variety in the scrolling background.  You can change the patterns anytime with opcode 06.

Opcodes

Corridor level data consists of opcodes.  There are 10, numbered 00-09.  Most of them have arguments that come with them.  Opcodes are followed by a 16-bit timer value that tells the engine how many ticks to wait before reading the next opcode.   If this timer value is 00 00, that signals the corridor engine to read the next opcode immediately.  I haven't worked out all of the opcodes yet, but here are some:

Opcode 00 - Scroll Speed

Opcode 00 sets the Scroll Speed.  It takes two arguments.  I'm still a little fuzzy on the exact mechanics of scroll speed, but changing the second argument seems to have the most direct effect.

Opcode 01 - Set Metarow Base

Opcode 01 sets the Metarow Base.  It takes two arguments, which is a pointer to a metarow base header.  The header is 3 bytes.  The first two bytes is a pointer to the first 16-metatile row of the metarow base, and the third byte tells how many rows there are.  Each rows' data is 16 bytes of metatile ids.

Opcode 02 - Set Monster Clock

Opcode 02 sets the Monster Clock.  It takes two arguments, which is a pointer to the Monster Clock data.  Like everything else in the corridor engine, monsters run on a timer that is based on metarow draws.  I call it the Monster Clock to avoid confusion with Opcode 07.

Monster Clock data has two types that I've seen so far:

1) Monster type: This type is two bytes: a monster id followed by a timer value.  The monster id tells the engine what monster to create.  The timer tells how long to wait before reading the next set of Monster Clock data.

ex: 1C 64 = load monster 1C (green comet), and wait 64 ticks before reading the next monster in the Monster Clock data stream.

2) Monster Generator type:  This type is four bytes: a monster id with bit7 set, a count, a generator timer, and a timer value.  The monster id (chop bit7) tells the engine what monster the Generator will generate.  The count tells how many of those monsters to create.  The generator timer tells how many ticks (metarow draws) to wait in between each monster generation.  The timer value tells how long to wait before reading the next set of Monster Clock data.

ex: 9C 0A 78 64 - create a Monster Generator.  It will create monster 1C (green comet).  It will create 10 of them.  There will be a 78 ticks interval in between each one.  Wait 64 ticks before reading the next monster in the Monster Clock data stream (note the next monster will be read before the 2nd green comet is generated).

Opcode 03 - Not Sure

I haven't encountered this opcode yet.  Looking at the code it appears to mess with the corridor timer.

Opcode 04 - Set Palettes

Opcode 04 sets the palettes.  It takes a two-byte argument which is a pointer to a list of 8 palette ids.

Opcode 05 - Load Boss

Opcode 05 sets the boss flag, which tells the game to start playing the alarm claxons and load the boss for the corridor.  It works a little differently for the Gauntlet corridor, in that it loads the bosses as regular monsters.   The boss to be loaded is read from a table using the Corridor Number as an index.  The boss table is located at 0xd161.   The boss song table is located at 0x0d178.

Opcode 06 - Configure Metarow Patterns

Opcode 06 is the workhorse.  This is where you set up all of your Metarow Patterns.  It's complicated and it's 1am right now, so I'll fill this section out later.

Opcode 07 - Load Monster Sprite Graphics

Opcode 07 loads monster sprite graphics from ROM and writes them to CHR-RAM.  It takes a two-byte argument which is a pointer to a list of CHR-RAM block ids

Opcode 08 and 09 - Not sure

I haven't encountered these opcodes in my tracing yet, but #09 looks like it messes with the corridor timer.

Conclusion

That's all for today.  I'll try to fill in Opcode 06 tomorrow, and fill in any details I missed as I figure more stuff out.
My NesDev blog: http://tummaigames.com/blog

optomon

Well, you can color me amazed. This is what I'd say is what I'd say is a solid textbook description of the corridor format, certainly better than I could have done. You called those 00-09 hex numerals opcodes which I thought was interesting. I would have called them "indicators". Heh... shows what I know. I think it's safe to say you've officially outnerded me in knowledge of the Guardian Legend rom. Bravo! :bluelander: And I love the exemplary images. Definitely keep going.

When I switched the bosses all I did was swap one of the 07 opcode operations from one corridor to another and of course switched the boss bytes from the 0xD178 table. Does that make sense?

TrickyCC

Little bit curious if you can find these values with the simple Cheat function in like Nestopia or using a 3rd Party Software/Emulator?
Felt really for trying this out and experiment with the original game.

tummai

Quote from: optomon on March 17, 2010, 01:50:38 AM
Well, you can color me amazed. This is what I'd say is what I'd say is a solid textbook description of the corridor format, certainly better than I could have done. You called those 00-09 hex numerals opcodes which I thought was interesting. I would have called them "indicators". Heh... shows what I know. I think it's safe to say you've officially outnerded me in knowledge of the Guardian Legend rom. Bravo! :bluelander: And I love the exemplary images. Definitely keep going.


Thanks!  I hope we can document as much of this game as possible so that anyone can jump right in if they want to.  There's still plenty I don't know though (esp. overhead map stuff).

Thanks for sharing your corridor document on RHDN, btw!  I had an idea of how opcode 6 worked, but I hadn't written anything down so it was a little vague in my head except for when I was sitting right in front of the debugger.  Your doc has already helped me a lot.

I used the term "opcodes" because of how the game code deals with those numbers.  It uses them as indexes into a table of code pointers (as opposed to data pointers), ie it pulls an address from the table and jumps there (actually, in this case they use the RTS Trick, but same idea).  When bytes from a data stream are used this way they are usually called "control codes" or "opcodes".  "Indicators" is a perfectly fine word to use too, just not as specific as far as what is happening under the hood.

"Metatile" is a term used by NesDev people to talk about a larger tile data structure that is constructed from standard 8x8 pixel NES tiles.  Most games (including TGL) use 2x2 metatiles (ie 16x16 pixels).  Some encode them even larger than that.  Using 2x2 metatiles means you can declare a row in 16 bytes instead of 32.  So it's a way to compress map data too.  There's a good description of it on this Nesdev blog (4th paragraph).

But I made up a lot of terms too.  "Metarow base", "metarow pattern", "monster clock" aren't commonly used terms as far as I know, especially monster clock  :bluelander:.

QuoteWhen I switched the bosses all I did was swap one of the 07 opcode operations from one corridor to another and of course switched the boss bytes from the 0xD178 table. Does that make sense?

Yes, makes perfect sense.  Opcode 07 loads monster graphics, so it makes sense that it would be paired with the boss opcode (opcode 05).
My NesDev blog: http://tummaigames.com/blog

tummai

Quote from: TrickyCC on March 17, 2010, 06:18:39 PM
Little bit curious if you can find these values with the simple Cheat function in like Nestopia or using a 3rd Party Software/Emulator?
Felt really for trying this out and experiment with the original game.

If the emulator has a hex editor built in you can change things on the fly.  FCEUX has one.   I think Cheat functions usually monitor RAM, so I don't know how useful they would be for finding/editing corridor data.  I think you need a hex editor.

Cheat functions are great for changing variables though.
My NesDev blog: http://tummaigames.com/blog

optomon

Well maybe you're right and I'm getting over my head, not giving myself enough credit and whatnot. 2x2 metatiles... That term could have helped. Guess that's what I get for being aloof in hacker circles over the years.

Anyway, something interesting to think about... corridor 21. Now there's a unique stage. I never really looked into it until a few days ago. Multiple enemies and bosses coexisting before the end of the level. And screens repeating over and over again. Maybe some of those uncertain opcodes are used there.

Grimgrin

Here are the list of enemies in RAM area somewhere in address $0500 - $0550:

Corridor 0
83 - Blue oval things
9A -
9C - Green Comment
9B - Orange Comment
AB - ???
B7 - Defense System
E2 - Red jet fighter???


Corridor 1
C2 - Fish
B2 - ???
C3 - ??? Collor Red
C4 - Sea Horse
AA - Bubbles
A7 - Missle
C0 - Blue Fleepa

Corridor 11
C2 - Fish
E3 - Starfish
AB - ???
C3 - ??? Color Red
AA - Bubbles
E1 - ??? Color Blue
AD - Green Optomon
A2 - Green Optomon's Weapon
8B - Small bubbles

Corridor 12
C2 - Fish

Need better names for them.
Currently extending the game.

tummai

in general, bit7 in a monster byte is the monster generator flag.  If it is set, the object represents a generator that will produce multiple instances of a particular monster on a timer.

For example in corridor 0, the green comet is actually 1C.  However, if you set bit7 you get 9C which is a green comet generator. 

%00011100 - green comet: a single green comet
%10011100 - green comet generator: produces multiple green comets ($560-$577 = #enemies to produce, $698-6AF = frame counter until next enemy, $7A0-$7B7 = counter refill value)

Corridor 0:

1A = spinning diamond
9A = spinning diamond generator
62 = red ship
E2 = red ship generator
20 = satellite dish
A0 = satellite dish generator
1B = meteor ring

B6 is the square trap-door turrets
B7 is the large circle turrets
AB is the turret missiles
My NesDev blog: http://tummaigames.com/blog

Grimgrin

Awesome! Thanks!

QuoteOpcode 00 - Scroll Speed

Opcode 00 sets the Scroll Speed.  It takes two arguments.  I'm still a little fuzzy on the exact mechanics of scroll speed, but changing the second argument seems to have the most direct effect.

Found it in RAM at address $00B9 & $00BB. You can change the speed to fast and slow.
Currently extending the game.

Jigglysaint

#10
Quote from: optomon on March 22, 2010, 02:15:05 AM
Well maybe you're right and I'm getting over my head, not giving myself enough credit and whatnot. 2x2 metatiles... That term could have helped. Guess that's what I get for being aloof in hacker circles over the years.

Anyway, something interesting to think about... corridor 21. Now there's a unique stage. I never really looked into it until a few days ago. Multiple enemies and bosses coexisting before the end of the level. And screens repeating over and over again. Maybe some of those uncertain opcodes are used there.

From a search I did, I think the game does a check to see if you are in corridor 21, and if you are, don't sound the klaxons or stop the screen from scrolling upon defeat of a boss untill a certain point.

Edit:  Been looking through the corridor data and metatiles have a certain pattern to them.

From what I've seen, 06 sets up the metastructures.  The next byte seems to determine how the tile operates.  I noticed that 40 causes the next 4 bytes to read as co-ordinate info and as tile repeater info, plus the pointers.  When 60 is set, it only uses 2 bytes for x/y and the pointers.  When it's set to 80, it seems to indicate the end of the metastructures for that specific area.  The second nybble of the second byte seeems to be the structure ID, and like it's been said, it seems to go up to 8 structures at a time.  Now for all the structures that are being loaded, it doesn't have to keep using opcode 06, but instead uses that second byte as the start of the next metastructure data.  I've seen this occur with a game called Equinox, which has a complicated object structure that "builds" off of previous structures and saves space by assuming x/y or z, block type, or other information based off of the previous structure.  It even reads information from the previous room, which can lead to fun puzzles.  Of course Equinox is an entirely different can of worms, and this is the TGL board.

The other thing is that the metastructure data also seems to be similar in the overworld section.  Only difference is that it doesn't use opcodes to set the data up, but just goes there from a pointer table.  Also instead of having an x/y in two bytes, it has it only in one.  The actual level data for the overworld is done entirely differently using pre-defined interiors plus objects.

Grimgrin

Quote from: tummai on March 18, 2010, 06:44:39 AM
Quote from: TrickyCC on March 17, 2010, 06:18:39 PM
Little bit curious if you can find these values with the simple Cheat function in like Nestopia or using a 3rd Party Software/Emulator?
Felt really for trying this out and experiment with the original game.

If the emulator has a hex editor built in you can change things on the fly.  FCEUX has one.   I think Cheat functions usually monitor RAM, so I don't know how useful they would be for finding/editing corridor data.  I think you need a hex editor.

Cheat functions are great for changing variables though.

You should try Code Data Logger on FCEUX emulator. It's really cool when I understand on how to use it 3 nights ago. If you in Corridor 21 or any of them, make sure that the log is reset and start the logger. When you finished the corridor, pause the logger and save the striped rom and named it Corridor 21.nes or whatever you want to name it. And then you should be able to look for the data that you need.
Currently extending the game.

RandomSpriter

Holy crap this is how they did the game? O.o

Sounds complicated(For a new timer to understand this.)