Monday, 30 October 2023

'S' is for... nothing!

Just a quick one... still progressing on Vulgus, chipping away at the unknown variables.

Indications are that the letter 'S' does... ABSOLUTELY NOTHING! I can't find any cross-references to it in the code, other than initialisation and updating a counter (max=4) when one disappears off-screen. A watchpoint in the MAME debugger doesn't reveal any accesses to the variable either.

Somewhat puzzling given that the other two letters do affect game play.

Random Vulgus picture for attention

I've been working on ROMSET #2 in MAME, so I decided to load up ROMSET #1 and see if that had any references to the variable. Took quite some time (two sessions) to get to the point where I could analyse the code in some detail - because of all the jump tables used in the game - but couldn't find any other references. Similarly playing the game didn't trigger the watchpoint.

I did however notice one difference in game play logic, and there are more. Interestingly ROMSET #1 allows 10-character names in the high score list, whilst #2 is only 3 characters. When I've finished the RE I will go back and analyse the differences in detail.

Monday, 23 October 2023

It's official, collecting the letter 'D' is good!

I haven't posted in a while but I have been making quite a lot of progress on the RE.

I would say 90-95% of the code has been commented now. Most of the unknowns have to do with the gameplay 'AI' - variables that affect the difficulty of the game, and also a few areas of functionality that I know the exact purpose of, just not the specific mechanics. Those include unpacking background map data, and handling the movement patterns for the aliens.

The RE is somewhat complicated by the fact that there are multiple object tables; one for enemies that fire, one for enemies that don't fire, and one for the 'large' enemies - and these tables don't have the same structure! 😣 So when commenting the code, I need to remind myself which type of alien the routine is operating on. Quite annoying because they are relatively small, and it would have been perfectly acceptable to use the same structure even if some members were unused.

But I still seem to be able to make some progress each session; I think I've hit a wall but then make a breakthrough with a few variables. It's just a matter of continuing to chip away here.

On the subject of collecting 'D' from an earlier post, I can say with absolute authority that it is beneficial to the player. Here's what the Vulgus manual on Capcom Arcade Stadium on the Nintendo Switch has to say about it:

"Increases enemy firepower when it appears. Collect it to stop the effect."

Technically though, it's not about collecting them, but rather not failing to collect them. Each map area starts with a variable denoting the maximum number of enemy bullets allowable on the screen at any one time, with an absolute maximum of 6. Nothing changes when 'D' appears, but failing to collect a 'D' will increase that count by 1. Of course at some point in the game, it becomes a moot point because you'll eventually start the area with the maximum (6).

Not a 'D', but here's an 'E' just for attention

'E' & 'S' are related to other variables which I haven't examined in detail just yet.

There's also a bonus that appears at 150,000 pts and then again at every 100,000 until the last one at 550,000 pts. After that it doesn't appear again. I need to understand more about the actual bonus at this point - I've never seen it myself and was completely unaware of its existence.

I've also learned about the titular 'Vulgus' boss enemy which, again, I am yet to encounter in my own gameplay. I'll need to practice a bit more  - I'd like to get there without cheating - but I need to get my MiSTer repaired first. That's on the to-do list for the very near future. Or maybe I should install my Vulgus PCB in the lowboy and fire it up!?!

Sunday, 8 October 2023

Slowly taking shape

I've reached the point in the RE where the rate of progress is beginning to slow. On the bright side, I've probably commented about 75% of the code thus far, so I have a good idea of how it's all working, if not some of the finer details. What's remaining is mostly entwined with what I call the 'AI', or gameplay logic.

Last session I was getting a little frustrated with the lack of progress, but a few small gains and then actually taking a step back to look again at the bigger picture improved my perspective somewhat and, as a result, some of the higher level unanswered questions suddenly seemed to click into place.

I didn't get a chance to work on it again today, but after working out all the hardware sprite allocations I now know what I need to do next; identify how the various aliens are allocated to the different object tables. That should in turn assist in RE'ing some of the remaining variables, and the mystery of the letters!

More to come on that subject...

UPDATE: I'll just tack onto the previous post...

Really getting into the nitty-gritty now. I have a much clearer idea of object table and sprite allocation after tonight's session. One structure I thought was an object table actually isn't, though I don't really have any idea what it is at this point.

There's quite a bit of table lookup happening. I'm working on the data structures and routines for the (up to 9) objects stored at $E200, which include the 'normal' smaller aliens buzzing around. I've identified the STATE, TYPE, X,Y and DX,DY structure members, plus what I believe are the TIMER and COUNTER members. Other members I'm still not sure of. I've identified types/routines for two (2) specific aliens now, the others should be relatively straightforward to identify one I work through the code.

There's quite a bit of table lookup in the logic for handling aliens. This is for both movement and other gameplay-related logic. It's going to take quite a while to work it all out, and perhaps there are sections I never will.

I can say that collecting 'D' is at least beneficial to the player in one aspect... more I can't say yet.

Thursday, 5 October 2023

Answers and Questions

More progress tonight and more questions than answers.

I started looking at the 'object' data structure used in so much of the code. Byte $00 appears to be the state, and $01-$04 appears to be the (16-bit) object X and Y coordinates. The MSB of the coordinates are copied to the sprite registers. Or so I thought...

Turns out that is true only for the player bullets, thus far at least. The player bombs have different coordinate data AFAICT. This doesn't bode well for the other objects, and it may well be that each object type has its own data structure. Sigh.

One interesting discovery... player bullets are rendered as foreground tiles - not sprites! Each bullet can potentially span 6 tiles, so there is a lengthy process of calculating the foreground video RAM address, and a lookup of tile codes just to render a bullet. The bullet object structure stores the address each time it is rendered, so it can be used to wipe the bullet when it is moved/destroyed. Phew!

And it gets even stranger - it doesn't seem to call these routines in attract mode!?!

More to come...

UPDATE: I was curious about the bullet sprite vs tile issue, so I looked a little further into it...

During attract mode, the bullets are rendered as sprites, using hardware sprites 4-7.

During gameplay, the bullets are rendered as foreground layer tiles.

Here's the kicker though, and this threw me for a bit... when you coin up and start a game, and 'READY' is displayed on the screen - all handled by the 'gameplay' state machine, as opposed to the 'attract mode' state machine - the bullets are also rendered as sprites! As soon as 'READY' disappears, it starts using tiles!

What's more, you can fire (white) bullets when 'READY' is displayed, but as soon as it disappears, so do all the on-screen bullets! And any subsequent bullets fired are pink!!!

Why?

I haven't looked further into it, but I have my theory.

Firstly, during attract mode and when 'READY' appears, there are foreground tiles in the gameplay area (VULGUS title and READY text), so any bullets rendered as tiles would obliterate those graphics. In attract mode, the (sprite) bullets run behind the title and text, and even behind the score at the top of the screen. In gameplay mode, (fg tile) bullets disappear before reaching the score.

Secondly, with (only) 24 hardware sprites, I suspect the game designers wanted to make more use of the sprites for enemies and their bullets? Otherwise - why would you do it??? Presumably (I'll deduce this later) the attract mode gameplay screens are explicitly designed to use less sprites than the game uses at its most difficult!?!

I've never seen anything like this before! 😲

Tuesday, 3 October 2023

Vulgus RE progressing a little better than I initially expected!

Back from holidays (boo!) and although I haven't posted again, I've made quite a lot of progress over the last couple of weeks.

First I'll admit I haven't gone back to look at the map decoding - there was plenty to do in the rest of the disassembly that kept me occupied. Some of the aforementioned numerous variables have been identified, though there's quite a lot that I still haven't deduced, as many of them are only used in one or two places, and likely for enemy AI - they're always the most difficult!!!

Having said that, a huge portion of the code has at least been commented to a degree, if still missing some key elements of data. Aside from the map data, there appears to be a homogenous 16-byte 'object' data structure for every, well, object in the game, from the player ship, to bullets & bombs, and aliens. I've figured a few of those bytes out, and hoping I can focus on the rest now that I'm at home and have access to larger & multiple screens, notepads etc.

There's a not-insignificant amount of code for a few unobtainable self-test screens, which I've been able to see run via patching a few bytes. They threw me for a bit as I couldn't reconcile what the code was doing with what I've experienced in the game. TBH they're nothing more than a curiosity and not worth in-depth RE.

Speaking of non-insignificant amounts of code; the 'instructional' sequences showing the point scoring system is quite a chunk in its own right. I've identified the state machine responsible for the attract mode sequences and have documented parts of it, but not all of it.

Part of the instructional sequence - quite a lot of code required

My overall impression is that the code isn't exactly the best I've come across; Xevious was far neater and more efficient. There seems to be quite a bit of duplicated code, and routines called from multiple places when you wouldn't expect they would need to be. I think some of the logic is a little hap-hazard in the way it was put together. And the game actually looks a little un-finished, though those more familiar with the game probably won't be surprised to hear that. Aside from evidence in the gameplay, things like branches between different routines that are identical tend to support this theory.

And finally for this post; there's the debate over whether collection of the letters 'E', 'S' & 'D' actually help or hinder the player. I've found the code that handles this, though I haven't completed the RE so I won't say anything more just yet other than to note that initially, I thought them completely benign! That was because the code that 'collects' them doesn't actually do anything (as opposed to the code that collects the 'POW' pickups). However further analysis revealed that the code actually tallies how many you've MISSED, rather than how many you've collected!!!

My immediate focus will probably be on deducing all the elements of the 16-byte 'object' data structure - that should help identify some of the outstanding data variables. As I said, I have a few worked out thus far, and have guessed a few others, now it's time to nail them all down!

Saturday, 23 September 2023

Holiday project - Vulgus RE

Long time no post!

Truth is I haven't had the time or the motivation to work on any Retroports projects for the last few months as work and Real Life have both ramped up significantly. The good news is that although work has been a lot busier, I have been working on FPGA design and that has me thinking more about potential projects for MiSTer. But I digress...

For now, I've brought my laptop away on holidays and needed a non-development project to fill in my down time - usually later in the evening - and have decided to RE Vulgus. Vulgus is perhaps a little lesser known title, Capcom's first arcade game in fact, and although it didn't set the world on fire, it is a sentimental favourite of mine as I played it quite a bit back in the day.

MAME screenshot

The game is a vertical shoot-em-up and (the game) runs on a single Z80; fixed foreground (character) 2bpp layer, 4-way scrolling background 3bpp layer, and 4bpp sprites. There's a 2nd Z80 for sound, and a pair of AY-3-8910 sound chips. Nothing exotic about that configuration.

I've spent about 5 nights thus far doing RE and have made reasonable but not spectacular progress. There do seem to be quite a lot of variables and I must admit I've hit the hard stuff a bit earlier than I generally do in these exercises. I've deduced the program architecture, which is remarkably similar to Galaxian and Scramble - almost to the extent that it suggest some sort of prior/shared knowledge. I haven't read the history of Capcom in any detail, but it is interesting how alike they are.

In a nutshell, the game runs from the VBLANK interrupt, queuing low-priority commands for the background to process - mostly tasks like foreground-layer output and score calculation. The background simply runs in a tight loop waiting to process commands, while the interrupt runs a hierarchy of routines called in sequence via jump tables, with variables keeping track of which routines are to execute next interrupt. Scott (Galaxin/Scramble RE) referred to them as 'scripts', they can also be thought of as 'state machines'.

After hitting routines in every state that manipulate varying amounts of yet-to-be-deciphered data variables, I decided to turn my attention to the game map. Even that appears to be more complicated than I'd hoped; possibly stored as meta-tiles and decoded on the fly one row at a time. I think I know where the data is stored, I just need to do more work to confirm it.

In order to assist with the RE of the map, I went back and created the graphics conversion tool that I do for every project, that allows me to render palettes, CLUTs, tiles and video memory. It's not 100% accurate, but close enough; in fact the one layer that is 100% is the background layer! My tool has been hacked from project to project over the years, and was becoming quite unweildy, so I also took the opportunity to tidy it all up and simplify the process a little. The next RE project will be a bit easier again now.

Next task is to return to the code and work out a way to render the entire map, as I did for Xevious (although I was far from the first to do that). I'm pretty sure I'll be the first to do it for Vulgus though.

Whether this effort ultimately results in a transcode is not clear atm. It does have the 16x16 background layer tiles though, which make it a lot easier to port to the Neo Geo, especially with the scrolling.

UPDATE: some progress with the map decoding/rendering. I think I've identified the tables and live pointers for the map meta-tile data, map tile data and map palette data. There is a distinction between 'planet' and 'area', and I think you can travserse the entire map 3 times before it resets?!?

Thursday, 1 June 2023

Galaxian star field

I've been chipping away at Galaxian as updates come from jotd. It's all-but-finished now, with a few sounds to implement and/or debug on the Neo Geo, and the mystery of randomly disappearing bombs.

I've just finished implementing the starfield, although I realise now I made one mistake that I may or may not decide to go back and rectify. The end result would be practically indistinguishable though.

The starfield in Galaxian (and similar games) is generated in hardware with some rather simple circuitry. A maximal-length LFSR is used to generate - and scroll - the star positions, with some simple combinatorial logic to generate the colours and blinking.

The original (MAME's approximation anyway)

Of course there's no way to replicate that mechanism on the Neo Geo, so I had to come up with a way to implement something similar with sprites. I wanted to be as accurate as possible, and I think I've managed that (almost) except for the blinking pattern (which you couldn't possibly tell anyway).

The LFSR has a period of 131071 (2^17-1) but is effectively clocked twice per pixel which, given a 256x256 pixel virtual display, causes the starfield to scroll every frame. The combinatorial logic generates 252 stars each frame (which of course just repeats every frame). Star colours are derived from certain bits in the LFSR on that clock.

The Neo Geo requires just 16 sprites of 16 tiles each to cover a 256x256 pixel area - IOW 256 sprite tiles. The first step was to generate the stars using the same LFSR and render them in the respective Neo Geo tile, taking into account the relative rotations of both the Galaxian and Neo Geo displays. [I've since realised I made a wrong assumption about the orientation of the Galaxian display, which wouldn't be difficult to fix.]

Once I had the star positions, I had to think not only about the colours, but also the blinking. Fortunately the Neo Geo has an extensive palette which allows up to ~4096 colours on-screen at the one time. This allowed me to use a separate palette entry for each of the 252 individual stars. The only added complication was partitioning the palette entries across those 252 stars. I calculated that each 16-colour palette would be sufficient for one half (left/right) of each sprite. Not 100% efficient use of the palette, but easier to calculate and also code up.

Now to blinking. No prizes for guessing I used colour-cycling. With a unique palette entry for each star, I can blink any/all stars independently. But what algorithm should I use?

Although there are only 252 stars, each of the 16 sprites requires 2 palettes (with 16 colours/palette) for a total of 512 palette entries. So I came up with a 9-bit (Galois) LFSR that effectively selects a random palette entry (star) each clock - though not all entries correspond to stars of course. To blink the stars, I needed two (identical) LFSRs, each clocked at the same frequency, but out of phase. The leading LFSR would blank out palette entries, and the following LFSR would restore them. How long the stars are blanked out depends on the phase difference between the two LFSRs.

I played with them only briefly before coming up with an acceptable solution; the LFSRs are 1/4 of a cycle out of phase, and they're each clocked 4 times per VBLANK. This seems to give a fairly decent emualtion of the starfield in terms of blinking.

Not that anyone will ever notice any of this!

Starfield on the Neo Geo. Can you still tell it's Galaxian?

If I do go back and change the starfield layout (as mentioned above) I'll update with results. In theory it should generate the exact pattern of the original. Blinking will never be the same though.

UPDATE: It took just 2 simple changes to reverse the rotation of the Galaxian screen and re-generate the starfield. However I still can't visually confirm it's the same as the original. But it'll probably stay this way now regardless, as I need to manually render an opaque tile for the display masking sprites. Oh well, I tried...