Saturday, 10 December 2022

The hidden beauty of the Brag Spario and another bug!

Finally finished the transcode of the Andor Genesis (mothership) and its preceding entourage; the Sheonites, the Garu Zakato (big exploding bomb) and Brag Spario (chaser bullets). Oh and the escaping Bragza!

The Andor Genesis descends,
and the sprite-per-scanline limit is just being exceeded

Interesting things happen when you're invincible. Whenever I've played the game, when awaiting the Garu Zakato I've always lurked at the bottom of the screen in order to more easily dodge the bullets. The Brag Spario approach the Solvalou but disappear off the bottom of the screen when you dodge them.

Whilst tesing the transcode, I ventured right up to the top of the screen before the Garu Zakato exploded! Ordinarily, you'd be destroyed by the radiating bullets almost immediately. But being invincible, the Brag Spario started orbiting the Solvalou like a display of orbital mechanics! It looked pretty cool, but I suspected a bug in the transcode. However when I fired up the arcade original and tried the same with invincibility - the same thing happened!

The Brag Spario should have featured more prominently in the game, to show off their fancy flying!

I also found a bug in the game, and again, I verified it on the arcade original! When destroying the Andor Genesis core, you score more than the allotted 4,000 points! See below, where I scored 4,010.

Can't really show the Brag Spario in a screen shot,
so instead a blew up the Andor Genesis core

It all comes down to how the Andor Genesis is represented in the object table. Last post I mentioned it comprises 9 'body' objects, 5 objects for the 4 gun ports and central core, and a 15th 'master' object which initialises the other objects and is used as the reference for the sprite coordinates etc.

Well, the way the bombing code works is that whenever your bomb explodes, it loops through the first 16 objects (ground-based objects) in the object table, destroying any object within range of the explosion. This is how you can destroy multiple objects, such as adjacent Lograms and Zolbaks, on the ground with single bomb.

So when you bomb the core, it first matches the core object (object #14) and you score the allotted 4,000 points. But then it continues and also matches the master object (object #15). However the master object never initialises the POINTS value (incidentally, there is no value that represents 0 points). So you are awarded the point value for the last object to occupy that slot.

For the Andor Genesis in Area 9, the last object was a Zolbak in Area 8, and so you are awarded an additional 200 points. When I was testing in the above screenshot, I was starting in Area 9; no object had been previously assigned to that slot, so POINTS was 0, which represents 10 points. You may recall, this is the same reason the Easter Egg at the start of the game is also worth 10 points.

I guess this means I'm finally up to the flying objects. The handlers for these tend to be a little more complex due to the flight patterns and the AI that affects their behaviour. Should be fun... but I might see if I can finish off the SUB CPU completely first...

Friday, 9 December 2022

The Mother of all Objects!

Finally debugged the Sheonites. Aside from more than the usual number of bugs in the transcode, I also updated the RE with more accurate subroutine descriptions as a result of my debugging. As it turns out, the left and right Sheonites are almost identical, except for the fact that when they 'combine' just before leaving, the left-hand Sheonite object is destroyed, and the right-hand Sheonite represents both as it shoots up the screen.

Sheonites done and debugged - the game
would never have been the same without them!

Having completed the Sheonites I moved on to the Andor Genesis (mothership). There was a bit of code in the SUB program that I had to transcode, and then work out which part(s) of the MAIN program handlers I had to implement first - the Andor Genesis comprises no less than 15 distinct objects in the object table.

In my RE up until now, I sped through the Andor Genesis handlers using 'place holder' names for all the parts. Now that I am implementing them one-by-one, I can actually back-annotate which part of the ship is handled by each object.

The ship comprises nine (9) 2x2-tile sprite 'body' objects (3x3), overlaid with 5 objects (sprites) for the turrets/reactors, and one 'master' object for the entity as a whole. I had to implement the latter object first, as all other objects reference that for state, position, etc. Thus far I have implemented the master (in part at least), the 9 'body' objects and one turret/reactor (bottom right).

Andor Genesis - partly complete

Xevious maintains a table of 64 objects - or rather a set of tables - that includes a table with the function handler address. As you'd expect, handlers (ordinarily) operate on the object with the same index as the handler is currently executing from. eg. A handler in slot #4 is operating on object #4.

The Andor Genesis, however, is unique in that a whole bunch of handlers - the 'body' handlers for example - don't reference the current object at all, but rather comprise hard-coded references to another object in the table. eg. The handler for object #1 (explicitly) modifies object #9 instead.

I can't say for certain why this has been coded this way, but it looks like they've had to reverse the order of objects in a hurry, and for some reason, they've chosen to do it this way. I should note that the lookup table for objects that comprise the Andor Genesis is actually in the SUB CPU ROM, so perhaps that has something to do with it?

Anyway, I've tried to remain true to the original code, and have preserved this aspect in the transcode. It did have the potential to mess things up a bit if the offending objects weren't all benign, but fortunately they don't call any common routines that expect the object pointer in A5 to be consistent with the index of the handler. Conversely, the not-so-benign turrets/reactors are in the right 'slot', so routines like firing at the Solvalou work properly without juggling registers.

I have seen the 96 sprites-per-line limit again with the Andor Genesis. In line with each turret there are actually 8 Neo Geo sprites, and that's without bullets. Line up the Solvalou to bomb a turret and that's another 4. Add a few bullets... that 20-sprite overhead is getting eaten up quickly.

I had the idea of turning off the middle of the tilemap layer during gameplay, as only the top 2 lines and bottom line or so is ever used during a game. A few more lines are used during attract mode, but it would at least give me another 12-30 sprites head-room...

Thursday, 8 December 2022

Much ado about nothing!?!

Even more RE as I wade through the code for the Garu Zakato (big exploding bomb) and the Sheonites (spinning pyramids) that precede it.

The Garu Zakato explodes with 16 radial bullets
and 4 Brag Spario that target the Solvalou

I can't quite believe the amount of code - some 409 lines assembling to 610 bytes - devoted to two objects that have absolutely no bearing on the game whatsoever! Incidentally, the 68K code is almost exactly half that, some 200 lines.

For those not intimately familiar with Xevious, there are two Sheonites that appear to mirror each other perfectly. They decend from the top of the screen, 'dock' with the Solvalou for a handful of seconds, and the join together before shooting off the top of the screen again. They are indestructible, and serve no purpose whatsoever other than be something to look at.

One of the Sheonites appears to be implemented correctly,
the other, not so much...

It would be perfectly reasonable to assume that they are both handled by the one routine. But it's a strange mix; two independent routines that share a lot of (duplicated) code, but are oddly asymmetrical. And one of them is explicitly destroyed; the other left to be cleaned up after leaving the screen. I've yet to debug the transcoded routines completely, but it has left me scratching my head.

When I first implemented one of the Sheonites, it stubbornly refused to appear at all. Eventually I discovered that the object handler wasn't being called, and that was because a few objects were inadvertently skipped when the handlers were scheduled. In the process of looking for the bug, I decided I didn't quite like the way I'd written the round-robin scheduler, and in the process of cleaning it up and optimising it, I found the bug. Two birds with one stone...

I think I will tackle the Andor Genesis (mothership) next after debugging the other Sheonite. Part of that code comprises the last remaining section of the SUB CPU program to transcode. Nothing tricky at all, just lots of hard-coded references to object attributes.

Sunday, 4 December 2022

More RE and more transcoding!

Some progress in small chunks over the weekend. I've now finished all the (23) ground-based objects, and moving on to the flying objects that are explicitly defined in the map data. These objects don't vary with the difficulty/AI level. So far I have done a lone Kapi, Terrazi, Torkan and currently working on the Garu Zakato (big exploding bomb in Area 9).

Garu Zakato WIP

I've been forced to do more of the RE in order to complete the implementation of the last few objects. So much of the code has been understood now, the last few routines are falling into place fairly easily. For instance the Garu Zakato loops through the bullet objects looking for 16 idle bullets, and initialises them in turn with every 2nd angle in the firing angle table; something I had no idea about until just a few days ago. It also creates a further 4 (flying) objects in the table - objects I had been unable to identify until now.

During my testing I've finally seen evidence of the Neo Geo's 96 sprites-per-scanline limit being exceeded. It's a bit of a false alarm atm, because I'm not optimising sprite usage, and the skipping of areas that produces the "bullet-hell" effect isn't realistic. The good news is that it will be very easy to identify if/when it happens, as the last sprites in the priority - the first ones that will not be rendered - are what I call the "visible display masking sprites" at top and bottom of screen, and mask the 'bouncing' effect of the scrolling background layer.

Saturday, 3 December 2022

Transcoding is flying along!

Progress has been relatively quick through the ground-based objects; it has mostly been a case of filling out a few more simple instruction sequences for handlers that were half-finished. Most of the lower-level routines used in the handlers have already been transcoded and tested.

The first flying enemy has appeared; the lone Kapi in Area 7. Unlike almost every other flying enemy in the game, its appearance is not contingent on the difficulty level nor the AI and as such, it appears explicitly in the map data. Although not technically a ground-based object, it is handled in the same manner.

A lone Kapi appears in Area 7

A total of 21 objects now fully transcoded and tested. That includes no less than 9 variants of Grobda (tanks) exhibiting 7 distinct behaviours; I think there's just another 2 variants to code. And just the one (flying) object left until Area 7 (ground-based or more correctly explicitly from map data) is complete.


Friday, 2 December 2022

Progress is on target!

I've fixed the shooting routines; now there's no doubt they're all targeting the Solvalou!

Those Derotas are on target!

The "bullet-hell" I was seeing had me concerned; it's not as if the firing frequency logic was all in one routine - every object has its own logic, even if it is essentially the same sequence of instructions. But how can that be wrong for every object?

Fortunately it wasn't a mystery for very long at all. The firing frequency for each of the ground-based objects is encoded within the map data, so that as you progress through the map, certain objects fire more frequently to make it harder.

Now I have a build option that lets me specify the starting level, so I can quickly test specific areas of the game. But when I start at a later level, the firing frequency parameters of some/all of the objects haven't been set (as those areas of the map have been skipped) and all hell breaks loose! If I start at level 1, the problem disappears.

I'll now continue with the next ground-based object in Area 5.

Fun fact: encoded within the map data is a parameter that determines at which row on the screen the ground-based objects will stop shooting. This is obviously another variable to temper the difficulty of the game as you progress through the areas.

The Garu Derota (large octogon) is the only grond-based object I've completed thus far that ignores this variable and does NOT stop shooting at the Solvalou until it scrolls off the screen!

A shot in the dark at how this all works!

Today I decided to implement bullets which meant going back to RE some of the code that calculates the bullet trajectory. TBH it did (and still does) my head in a bit; I understand what it's trying to do and roughly how it's doing it, but some of the finer details still escape me. That's not absolutely critical as long as I can replicate the effect of each instruction (or routine). I freely admit that I had to resort to this approach in a couple of low-level routines in Knight Lore, for example.

The lowest level routine takes the absolute values of a (dX,dY) pair between source and target and calculates the ratio of the smaller to the larger; IOW the tan of the angle in the 1st octant. That gets scaled from 0.0-1.0 (0-256) down to 0-32 which then indexes into a table that in turn returns another value (0-32) from a non-linear but monotonically non-decreasing distribution. Looking at a graph of this distribution (below) it doesn't make a lot of sense to me atm*. Then it adjusts this value for 2nd octant if applicable by examining whether dX or dY was larger, and finally adjusts for the correct quadrant by examing the signs of dX & dY in turn.

The function that is applied to the tan of an angle in an octant

* Does this function correct for pixel aspect ratio, so that bullets splay out at regular angles on the screen (and/or at the (purposeful) expense of accuracy)?

That final value is scaled (again) from 0-31, and used as an index into a table of (dX,dY) pairs for bullet trajectories. IOW, objects can fire at 32 different angles.

It has all been transcoded but not debugged; the trajectories are definitely not correct and the ground-based objects seem to almost always shoot in a SW direction regardless of where the Solvalou is located on the screen.

That Garu Derota is firing way too quickly -
Xevious is not supposed to be a bullet-hell!!!

Some objects also seem to be firing a lot more frequently than they should, but that's another issue.

On the note of firing frequency and AI: none of the gound-based objects' behaviour (for the objects I've completed at least) is contingent on the difficulty level set by the dipswitches, nor the adaptive AI logic that depends on the player's skill. The dipswitches and AI level only seem to affect the flying enemies.

When the RE is complete, I'll do a comprehensive analysis of the difficulty settings and the AI logic.

Until then, I need to debug the bullets and the firing logic of a few objects it seems...