Wednesday, 30 November 2022

Progress is on-path!

Domogram was one of the more complicated ground-based objects and I must say the implementation went pretty smoothly. It's the object that seemingly 'follows' paths.

The circling Domograms on Level 7

Of course it's all pre-canned routes programmed via a list of vectors comprising dX,dY and length components. The map data encodes a single byte for the dX,dY pair, which is an index into a table of actual values for the pair. Each Domogram can have up to 64 bytes (32 vectors) programmed into a circular buffer that can hold path data for up to 12 Domograms on-screen.

Up next, Derota. That will incidentally finish off the ground-based objects for Area 2.

UPDATE: Derota finished!

UPDATE #2: Garu Barra, Garu Derota and another Grobda variant fnished, rounding out Areas 1-4 for ground-based objects.

Garu Derota, before being destroyed

The Garu (big) objects comprise a 2x2-tile sprite overlaid with a 1x1-tile sprite in the centre. When the centre sprite is hit, it is removed to reveal the 'destroyed' 2x2-tile sprite. Obviously this requires the centre sprite to have display priority over the larger... fortunately the sprite priorities of the arcade board and the Neo Geo are compatible - it would have been a minor inconvenience to (programmatically) reverse the orders in the code, but not insurmountable.

The next Grobda to appear in the game (Area 3) was one of the 'duplicated' variants. Implementing the Garu objects had given me a hint as to why this could be (indicated by a common graphics glitch before transcoding was complete), and I quickly confirmed it. Although the behaviour of the two Grobda is exactly the same - in this case moving forward when targeted in the crosshairs - one of the Grobda leaves a crater when destroyed, the other simply disappears. The latter, as it turns out, appears on water (where obviously it sinks when destroyed).

Another example of something that can easily be missed in a static analysis.

One gound-based object (technically, 16 objects) that I haven't implemented yet in Area 4 is the Andor Genesis (mothership). I figured I'd leave that until the last of the ground-based objects.

Although the ground-based objects do (visibly) 'fire' back at the Solvalou (and the animation is complete), the bullet objects have not been implemented. It's difficult to tell, but some of them appear to be firing a crap-tonne of bullets, and I'm not sure there's no bugs in that part of the code. So I'm thinking it might be time to implement the bullets - even if they remain harmless atm - just to get an idea of whether the firing logic is correct.

Oh and I fixed the background layer display of tiles from the 2nd bank.

The Nazca Lines are now rendered correctly (again)

Monday, 28 November 2022

I like big Booms and I can not lie!

Well, that was a little easier than I first thought! Maybe because I implemented it incrementally, 2x2-tile sprite support is now (mostly) working. Explosions and Garu Derotas at least are good. I suspect I need to handle flipping differently for 2x2-tile sprites, because Sol Towers don't look right. It'll be a bit ineffcient but fairly straightforward. Right now I'm not concerned with code optimisation.

BOOM - 2x2 tile sprite explosion!

I had a choice of whether to program the 2nd chained sprite in the shadow registers, or on-the-fly as the sprite hardware is being updated. Programmatically it wouldn't have made much difference, as the 2nd sprite only needs tile codes, colours and the chain bit to be programmed.

I was undecided until I remembered that the latter is updated in the VBLANK interrupt service routine, and as such efficiency is critical. Much more efficient if the shadow registers are updated in the main program loop (which should be spinning idle by the time the next VBLANK interrupt fires) and simply block-written into VRAM.

Xevious is now using 266 of the 384 usable sprites on the Neo Geo. They are not all active at the same time, but there will be times when it could run very close to the 96 sprite-per-scanline limit. As I mentioned, there are 75 sprites always active on any 1 scanline at a time, not counting the Xevious sprites. Cutting it fine, but I think I'll get away with it.

UPDATE: I have fixed the 2x2-tile sprite code and all the sprites I have seen thus far in the first few levels are correct. It wasn't a flipping problem, but rather the details of how the sprite codes are mapped amongst the 4 individual sprites. I also fixed a (seemingly) benign bug in the sprite rendering code.

The Sol Tower is finally rendered correctly!

Another issue I had to fix at the same time; because of the difference in coordinate systems, the 2x2-tile sprites need to have their X coordinate adjusted with respect to 1x1-tile sprites. Initially the adjustment was done simply when updating the shadow registers, but then tonight I noticed I could no longer destroy the Sol Tower once it had risen!?!

I quickly realised that it was the sprite X coordinate adjustment that was breaking the bombing-detection routines that use the shadow registers (as I mentioned in a previous post). I looked at moving the adjustment to the sprite hardware register updates, but there's not enough information to (efficiently) determine when the adjustment needed to be made. It's also not ideal to spend more time than absolutely necessary in the VBLANK ISR. It was then I had the idea to have the code write two versions of the shadow registers (for the X coordinates only); the original coordinates for bomb-detection, and the adjusted coordinates for hardware register updates.

In hindsight I'm a little surprised the implementation for 2x2-tile sprites was completed in a day, and as it turned out I had procrastinated for no good reason. It certainly looks a lot better, and I am even closer now to being able to declare that - sound aside - the OSD code is complete.

There are still a few glitches that I have ignored until now; occasionally the score (foreground tilemap layer) is just a black bar, and the map isn't displaying the tiles from the 2nd bank (not visible until later aeras, and I'm sure it was at one point previously). I'll proably continue to ignore those until I get to optimising the OSD routines.

For now though, I'll continue with any new ground-based objects that appear in Area 2. First up is the Domogram - the round vehicles that follow paths and fire at the Solvalou. The RE for them is complete, so I know what I'm up for. FYI they blindly follow pre-canned paths, cleverly designed to give the illusion of some sort of ability to actively avoid Solalou bombs. They won't be the first moving objects that have been (at least partially) transcoded (Grobda claim that prize) but will certainly add to the dynamics of the screen once they're done.

Sunday, 27 November 2022

The making of a Boza Logram.

Finished off the handler for the Boza Logram (Dome Array) this evening. It was surprisingly complicated; some 277 lines of Z80 assembler, transcoded to 146 lines of 68K assembler.

The Boza Logram is represented by just 2 bytes in the map data; the type ($2D) and the Y coordinate of the sprite (left/right position on the display). From there, the initial handler creates 4 more objects - another 3 for the outer Lograms and one for the centre. In the process it patches the handler table for all 5 objects with new handler functions, and sets up the sprite X & Y coordinates, states and attributes.

Without going into too much detail, the subsequent handlers are responsible for setting up sprite codes, animating the sprites, firing at the Solvalou, checking they've been hit, and exploding - not unlike other handlers. The centre handler also destroys the outer Lograms when it is hit, and conversely the outer Lograms update the points value of the centre (600 pts down from 2,000) when they are hit. A lot going on.

The Boza Logram is ~277 lines of Z80 ASM

When I was actively working on the RE, I thought the initial handler installed the subsequent handlers in a 'callback' table for each object. At the time I didn't think much of it, and they were eventually all-but-forgotten as I proceeded with the RE.

Of course, when it came time to transcode this handler I wrote the new code to copy the handler addresses into a new 'callback' element of the object table, and immediately realised I didn't know how these callbacks were invoked!?! It wasn't long before something twigged, and I realised the 'callback table' was in fact the main function handler table - these weren't callbacks at all.

I have since updated the RE and the 68K source, but it goes to show that you don't always get things 100% right when doing a static analysis. I'd claim that when, and only when, the transcode is complete, the RE will be 100% accurate and true.

As far as ground objects are concerned, Area 1 is now complete (although they don't actually spawn bullets when firing back). That's 8 distinct object handlers done and dusted. Only ~55 to go (though 16 of those alone are for the Andor Genesis aka mothership)...

Not 100% decided what I'll tackle next; either finish off the 2x2 tile sprite support, handle ground-based objects shooting back, start on some flying objects, or move onto the next ground-based object handler.

FTR the main CPU code (68K) is now around 3,000 lines, the Z80 equivalent is 11,000 lines. If I assume the 68K will end up at approximately half the number of lines, it means I'm about 54% of the way though the transcode of the main CPU code. My gut tells me that sounds about right. I'd also guess that the SUB CPU code is around 95% complete.

UPDATE: just added a build option to display the area (technically, in base 17) on the bottom right corner of the display.

Fun fact: Hitting the centre of the Boza Logram (first) is worth 2,000 pts. If you hit both it and one of the outer Lograms at the same time (with the same bomb), you'll get an additional 300 pts for the outer Logram. Hitting an outer Logram first scores 300 pts but will reduce the centre value to 600 pts.

Saturday, 26 November 2022

Sprites: bigger and better!

I'm working through the object handlers in the order that they appear in the game. So far I have the following complete; Easter Egg, Barra, Zolbak, Logram, Sol Tower, Grobda (stationary) and the Bonus Flag. You can bomb them, score from them, and (where relevant) they disappear in a crater. The last ground-based object in Area 1 is the Boza Logram, which I haven't done yet.

Fun fact: the Easter Egg is worth 10 points, only because bombing anything updates the score from the object table 'POINTS' element and the (default) value of 0 (after the table was zeroed) equates to 10 points in the game.

Although the Logram "fires" bullets at the appropriates times, the code to spawn a new bullet hasn't been written. Technically that simply creates a new 'bullet' object and isn't strictly part of the Logram object handler once it leaves the opening, so I can say the Logram handler is complete.

It's also worth noting that there are a few object handlers in the code that aren't actually used. These are mainly identical copies or variants of objects that are used. One example is a Logram variant whose firing frequency isn't actually defined, and if used, I believe would use the firing frequency of the last object that occupied that slot in the table.

At this point I've started to work on support for 2x2 tile sprites. All the explosions, and the Sol Tower, comprise 2x2 tile sprites, as well as a handful of other ground-based objects in the game. To this end, I have 2x1 tile sprites (double height) coded and tested. In fact one half of the explosions are right now. That was the easy part; simply setting the (NeoGeo) sprite height to 2 tiles and adding the approriate sprite code & colour. Note that AFAIK, only 1x1 and 2x2 tile sprites are actually used by Xevious.

Half of the explosion (2x1 sprites) is right now

The way I plan to add support for 2x2 tile sprites is to double the number of NeoGeo sprites allocated to the Xevious sprites, and simply chain pairs together to get the double-width element of the equation. There will need to be some tweaking of the coordinate because of the difference in coordinate systems between the Xevious arcade and the NeoGeo, but I'm hoping it won't be a lot of work.

What I do have to be wary of though is the 96-sprites-per-scanline limitation on the NeoGeo. The foreground tilemap layer is currently 36 sprites, the background is currently 37 (active) sprites, and adding the two visible display masking sprites makes 75 active sprites on EVERY scanline so far. Given that there are up to 64 sprites on Xevious, I'm going to have to ensure that NeoGeo sprites are only activated when absolutely required.

That's going to be a little bit of work and probably a few days before I get it working properly. Then I think the OSD layer on the NeoGeo will well and truly be finished.

Friday, 25 November 2022

Shooting for the stars (in the absence of anything else to shoot at)

Quick lunch update; shooting is now working (there's nothing to shoot at though).

Up to 3 Solvalou bullets can be active on the screen

I've also indentified an area of shared RAM which appears to be used to signal the SUB2 processor to start/stop certain sounds during the game. This ticks off a handful of variables in the RE whose purpose was unknown until today.

Next up, having bombs actually blow things up! The scoring should already be in place, although things like updating the high score and awarding extra Solvalou have not been transcoded yet.

UPDATE: Slow afternoon (the best type of Friday afernoon) and so I managed to do a bit more Xevious. Bombing is now complete; you can destroy any objects whose handlers have been transcoded up to the point where they check they've been hit.

It's always fun blowing things up!

There does seem to be a glitch in the routine that displays the score... almost as if interrupts aren't disabled when VRAM is being accessed; sometimes the score is a black line?!? Hmm....

Targeting the... targeting code!

More progress today, and some further complications arise.

I've coded the 'targeting' function where the crosshairs flash red when hovering over a ground-based object, including the hidden sol towers.

Cross-hairs flashing red over a Sol Tower

Herein lies the complication; the Z80 code uses the shadow sprite RAM for coordinate comparison between the crosshairs and the ground-based objects. Similarly, the shadow sprite RAM is used in other 'collision-detection' routines, like collecting the bonus flag. The issue is, the shadow sprite registers are in OSD - in this case Neo Geo - format, and idealy only accessed in the OSD layer.

For now, I've ignored that fact and just written the code in the main CPU file. But of course ultimately it can't reside in this file because it's strictly a platform-independent core.

Moving it into the OSD layer is troublesome from a few angles, not least of which is efficiency (especially if I write accessor functions for sprite coordinates). And I can't move the whole routine as I also don't want any core game logic in the OSD layer.

On the 68K core though, the sprite coordinates stored in the object table are simply 16-bit values, scaled with respect to the Neo Geo register copies in shadow RAM (themselves shifted into high bits). It would therefore be no less efficient to compare sprite coordinates from the object table as opposed to the shadow registers. I'll sit on it for now, but I will probably go this way; deviating from the original code, but arguably only semantically.

Other progress comprises being able to collect the Bonus Flag, and score either 10,000 pts or an extra Solvalou, depending on the dipswitch setting. I have a build option for revealing the location of the Sol Towers. And finally, I've coded the shooting routines, but haven't debugged them yet. Shots are fired, but they don't behave as expected.

10,000 pts for collecting the Bonus Flag

Next is obviously debugging the shooting, and then I'll code the routines for bombing ground-based objects. They should be very similar to the targeting routines I did tonight. Then there will be a lengthy process of finishing all the handler routines for the ground-based objects.

One last aspect of the OSD layer I need to add is the 2x2 sprite hardware support. I have an idea of how that's going to work, but I will probably leave it for a while yet.

Thursday, 24 November 2022

I hate computers. Mine is bombed...

%$#@^%!@$#%^!$@&^#%$&!@^%#$&!%@^$# PCs... another machine crash.

Despite that, have implemented bombing. Nothing gets hit or explodes, but you can drop bombs.

Encountered an interesting complication; Xevious sprites can have more than 1 color entry as 'transparent'. The crosshairs that are also used for the bomb target use different CLUTs at different times, and some of them have transparency set for pixel values 0, 2&3 simultaneously. That means I will have to modify the source to use different tiles for the sprite at different times...

Don't know how many days I'll waste trying to restore my PC. I don't even know what the failure was atm. I thought it was the RAM, which I changed, and it seemed to fix it, but then it stopped booting again when trying to install NVIDIA drivers... grrr!!!!!