2 Player F-Zero Feasibily

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
2 Player F-Zero Feasibily
by on (#142016)
Okay, I'm not saying I want to try and make this or anything, but I always enjoyed F-Zero but found its lack of 2 player disappointing. I know how Mario Kart can do it and it seemed like it was purely a design choice, but I realized that the tile map in Mario Kart never appears to get updated, unlike F-Zero. Would this be the reason? I can't really think of a way to have 2 different tile maps given the weird nature of how mode 7 is set up. The only way I can think of it would be to change the data in the tile map mid screen using force blanking, but I don't think you would be able to update it in time without a huge gap between the top and bottom screens. I know that Super Mario Kart has a chip called the DSP-1. What is it for and what does it do? I've heard it helps the game have split screen Mode 7, but this is not very clear. Also, kind of off topic, but do you think that the SNES would be able to expand/shrink about 8 32x32 sprites through software in one frame? I hate the look of the choppy scaling in racing games that use pre rendered scaling sprites.
Re: 2 Player F-Zero Feasibily
by on (#142018)
The tilemap is updated sometimes in Mario Kart. The ice blocks in Vanilla Lake are on the plane.
Re: 2 Player F-Zero Feasibily
by on (#142020)
mikejmoffitt wrote:
The tilemap is updated sometimes in Mario Kart. The ice blocks in Vanilla Lake are on the plane.

But were talking about 2 separate tile maps for each screen.
Re: 2 Player F-Zero Feasibily
by on (#142022)
Why did you delete your post? I didn't think like that sounded like that bad of an idea. (Although I have no idea as to how you would implement it.)
Re: 2 Player F-Zero Feasibily
by on (#142023)
You just mean that the map doesn't scroll, so both players can share the same map data at all times.

From your description, I'm presuming F-Zero is very different than this, scrolling the map with wrapping. The wrapping makes it really hard to share, since you always need to keep the scrolling seam behind the player. Since there can only be one scrolling seam on a layer, only one player.
Re: 2 Player F-Zero Feasibily
by on (#142024)
Espozo wrote:
Why did you delete your post? I didn't think like that sounded like that bad of an idea. (Although I have no idea as to how you would implement it.)

It suddenly started to sound like I hadn't thought it through. The problem is that you don't actually have two tilemaps. They don't wrap at the middle; they wrap at the edges, so it gets difficult to prevent players from driving onto one another's maps. The Mode 7 map is big, but it's not that big...

Regarding sprite scaling, I guess I'll repost that link...
Re: 2 Player F-Zero Feasibily
by on (#142025)
The DSP-1 is doing the 3D point to 2D projection stuff. The pipes in mario circuit, the players, the bananas on the track, the shells.

It's doing polar coordinate stuff to do vector math. (I.e. what angle does the red shell need to travel to hit the nearest player higher in place)

It's at least helping out with that skewing effect that gives the illusion of convergence toward the horizon, although with some precalculated tables F-Zero is able to do it without DSP-1.




You actually bring up a good point. Since there is no way to change the memory offset of the mode-7 bitmap, it always takes up the bottom 32K of VRAM. So you really can't have two independent maps being rotated/scaled, just different views of the same map data.
Re: 2 Player F-Zero Feasibily
by on (#142027)
Exactly. 1024x1024 pixels is a bit small for a full fledged race track. You know, if you think about it, F-Zero was really about 20 years ahead of it's time, seeing that it doesn't allow split screen. I guess the only way to do 2 player (on one console :wink: ) would be to have a 64 pixel black bar. :? About the sprite scaling, is it uncommon to keep switching sprite sizes as the sprite shrinks so you don't run into the sprites per scanline limit? If you were trying to scale a tree in the background that is only 8x16, but its max size is 32x64, you're going to run into problems if there are more than 8. (Which there are going to be because of depth.)

Quote:
You actually bring up a good point. Since there is no way to change the memory offset of the mode-7 bitmap, it always takes up the bottom 32K of VRAM. So you really can't have two independent maps being rotated/scaled, just different views of the same map data.

Honestly, I've never understood why they made the setup for mode 7 so different than the other modes when it didn't need to be. (Unless it's some kind of hardware thing I'm not aware of.)
Re: 2 Player F-Zero Feasibily
by on (#142029)
Espozo wrote:
Honestly, I've never understood why they made the setup for mode 7 so different than the other modes when it didn't need to be. (Unless it's some kind of hardware thing I'm not aware of.)


It's totally a hardware thing. If you take a look at the schematics, the two video ram chips are independently addressed. Plus they are Static RAM and they are constantly being read, with no spare cycles to even think about a dram-style refresh. Really this is the best they could come up with at the time and remain affordable.
Re: 2 Player F-Zero Feasibily
by on (#142030)
Espozo wrote:
I guess the only way to do 2 player (on one console )

Oh yeah, has anyone ever made something like a "link cable" for the SNES? (I think I just beat my personal record of how fast I can derail a conversation here. :roll: ) (You know, it could almost be like one of those joined arcade cabinets:)

Image

Quote:
It's totally a hardware thing. If you take a look at the schematics, the two video ram chips are independently addressed. Plus they are Static RAM and they are constantly being read, with no spare cycles to even think about a dram-style refresh. Really this is the best they could come up with at the time and remain affordable.

Interesting... Well, it works completely fine the way it is, as long as you are "playing by the rules".
Re: 2 Player F-Zero Feasibily
by on (#142031)
How much graphics DMA is involved here? If you're scaling up to 8 32x32 sprites, that's 4 kB, but you shouldn't need to transfer that every frame. Every two frames, maybe, if not more. OAM shouldn't be full, and CGRAM doesn't change (much?), so there should be nearly 4 kB left for map updates. That's about a frame to rewrite a quarter of the Mode 7 tilemap.

If you could guarantee 4 kB of tilemap DMA every frame, you could just use two submaps of 4 kB each, and completely rewrite each one every other frame, preventing visible seams while also keeping players from crossing between maps. Scroll positions and tilemap position offsets could be tabulated based on angle of view to give maximum valid draw distance without garbage creeping in at the edges of the picture; that way you could maximize resolution without having garbage show up near the horizon...

It'd still probably look a bit blocky compared to the original, but I don't see why it wouldn't work. Split-screen squishes the picture anyway, so you get less detail and maybe a nearer horizon (though caution is advised when doing anything to an F-Zero game that might give players less time to react)...
Re: 2 Player F-Zero Feasibily
by on (#142034)
93143 wrote:
and completely rewrite each one every other frame,

Wait, how? From what you're describing, it seems like the game would run at 30 fps. Edit: Oh, you mean having two different spaces for each playfield, right? Maybe you could have 2 separate maps and also partially expand the bottom one using force blank. (I guess a 16 pixel black bar wouldn't look too bad? :? )
Re: 2 Player F-Zero Feasibily
by on (#142035)
Espozo wrote:
From what you're describing, it seems like the game would run at 30 fps.

No, the scroll position and matrix parameters, and sprite positions, would be updated every frame. But each player's tilemap and scroll position would be totally refreshed every other frame (alternating between players), to remove the necessity of wrapping. All you have to do is leave enough leeway for scroll changes during the off frame so that you don't get garbage onscreen. You might also be able to back a player's position up towards the edge of his tilemap a bit so as to get more data in view, partially mitigating the effect of the smaller map size and letting the tile resolution be closer to the original.

Quote:
Oh, you mean having two different spaces for each playfield, right?

No, but now that you mention it, that would allow you to double-buffer, if you couldn't manage 4 kB in one frame for some reason.

...this scheme does strike me as a pain to deal with DMA-wise...
Re: 2 Player F-Zero Feasibily
by on (#142046)
93143 wrote:
Quote:Oh, you mean having two different spaces for each playfield, right?No, but now that you mention it, that would allow you to double-buffer, if you couldn't manage 4 kB in one frame for some reason....this scheme does strike me as a pain to deal with DMA-wise...

Actually, Unless you have 2 parts of the tilemap being shared, You couldn't just copy all of the graphics for mode 7 because if I'm not mistaken, you cannot change the position of where you look for the information. It always starts at the beginning of vram, and even if you were going to copy the whole thing twice, you would have literally 0 space for anything else because it would take up the whole 64KBs.

Edit: Just look at this:

Quote:
No, the scroll position and matrix parameters, and sprite positions, would be updated every frame. But each player's tilemap and scroll position would be totally refreshed every other frame

Which one do you mean? I think you could get away with scrolling at 60 fps just fine, as I don't see anything wrong with it.
Re: 2 Player F-Zero Feasibily
by on (#142069)
Espozo wrote:
Actually, Unless you have 2 parts of the tilemap being shared, You couldn't just copy all of the graphics for mode 7 because if I'm not mistaken, you cannot change the position of where you look for the information. It always starts at the beginning of vram, and even if you were going to copy the whole thing twice, you would have literally 0 space for anything else because it would take up the whole 64KBs.

Each player's tilemap in my scheme is only 4 kB. One quarter of the Mode 7 tilemap. This might allow it to update in one frame, or perhaps two if there's no quick way to DMA it.

If a player's quarter-tilemap can't be updated in one shot, some method of double-buffering is necessary to avoid visible artifacts. But hey - there are two free quarters; the player can be switched between the quarter he's on and one of the free ones by altering the scroll parameters. So you can update the free one instead of the live one, and move the player when it's done.

Espozo wrote:
Quote:
No, the scroll position and matrix parameters, and sprite positions, would be updated every frame. But each player's tilemap and scroll position would be totally refreshed every other frame

Which one do you mean? I think you could get away with scrolling at 60 fps just fine, as I don't see anything wrong with it.

I mean both.

Each time the player is put on a fresh tilemap, his scroll position is chosen to maximize the viewable area of the tilemap based on his rotation angle, and the tilemap itself is chosen so that this procedure results in the player looking at the right tiles in the right places. But this doesn't happen every frame, so the player's position will move within this tilemap, and so there has to be enough margin in the initially-chosen position that the player won't end up seeing the edges of the tilemap before another refresh can be accomplished a few frames later.

This gives you 60 fps scroll, on top of a slower scroll update corresponding to the tilemap refresh.

In the attached picture, Player 2 (green) has just had his map refreshed and has been placed in an optimal position on it. Player 1 (red) is using an old map and has thus moved somewhat from his original position. The game will now proceed to update Player 1's map and position.

Attachment:
2pmap_fzero_p2update.png
2pmap_fzero_p2update.png [ 505 Bytes | Viewed 6889 times ]

Of course, the calculated optimal scroll position baseline (where the player is initially going to be put) is needed to define the tilemap, so depending on how fast the DMA happens, the result may be a couple of frames old by the time it's used. Adding normal scrolling to it every frame keeps it up to date so the player doesn't see any judder or lag, though it requires extra viewable-area margin because the player can now get farther from the baseline position before the next refresh.

...

Wait a minute; I just thought of something. What if both players got updated at the same time? With double buffering, there's no reason not to:

Attachment:
2pmap_fzero_halfupdate.png
2pmap_fzero_halfupdate.png [ 520 Bytes | Viewed 6889 times ]

In this pic, both players are on slightly stale maps (one frame old) and have thus both moved a bit from their original positions. New map data for both players has been properly compiled and interleaved in WRAM (ie: a miracle happens) and can thus be DMAed to VRAM in two big single-channel bursts instead of 128 little ones. The bright area is a single 4 kB DMA that has just happened. Next frame, another one will happen, and the players will be moved down onto the new maps.

...

Am I making any sense here?
Re: 2 Player F-Zero Feasibily
by on (#165038)
93143 wrote:
New map data for both players has been properly compiled and interleaved in WRAM (ie: a miracle happens)

It might be possible to do this manually on the S-CPU, but it would take a huge chunk of each frame*. It might work, as long as not much is happening (no AI racers?).

But if a special chip, such as the SA-1, were being used, it seems like it would be possible to build a 4 KB DMA-ready chunk of map quite rapidly, in maybe 6% of a frame or so. This number seems to be similar on the SA-1 and the Super FX, if I've understood things correctly. The SA-1 can use repeated DMA from ROM to BW-RAM to build the map out of 64-byte strips, and the Super FX should be able to use cached code to pipeline the data through the ROM and RAM buffers so as to saturate both.

Adding an SA-1 or Super FX seems like overkill for just hacking a split-screen two-player mode into F-Zero (which would probably be a substantial task on its own). It would probably be more appropriate in the context of a whole new game designed to use the full power of the expansion chip (which would be a monumental task, not to mention the copyright issue - but boy do I have ideas...).


*Block move is so freaking useless on the 65816; unrolled 16-bit indexed long -> indexed absolute is faster. And of course if HDMA is running, which it is, I can't carelessly use DMA because of that rev.1 CPU bug...

EDIT: I may have made an unwarranted assumption. This post and the next one should be taken with a grain of salt, if you can make sense of them at all.
Re: 2 Player F-Zero Feasibily
by on (#165074)
Wait a minute. If one were to completely turn off HDMA during backdrop/sky areas (so any gradients would have to be paletted), it would be possible to use DMA during that time without risking a deadlock on a rev.1 CPU. And if my math is right, doing this with DMA would take a little over 32 scanlines in total. So with a roughly Super Mario Kart-sized (20 scanlines) backdrop/sky in each player window, it might actually work, as long as the first player's map position can be determined early enough to get the first half started in time. I think the IRQ structure makes sense...
Re: 2 Player F-Zero Feasibily
by on (#165075)
I'm listening, but I have no clue what's going on... :lol: What are we transferring with DMA? It can't be the Mode 7 tilemap, because that's in vram, unless you're wanting to shift this around in ram. Oh yeah, didn't you say it was because of how you wanted to transfer data from the ram on a cart using an expansion chip? Why is this chip even needed again? Sorry... :lol:
Re: 2 Player F-Zero Feasibily
by on (#165092)
The problem is that while F-Zero as it stands can simply construct and DMA a couple of rows/columns of the tilemap on demand, switching out 4 KB of map data each frame is considerably more labour-intensive. I'm attempting to brainstorm methods of building a chunk of data in RAM (WRAM or BWRAM or whatever) that can simply be DMAed to VRAM in one shot during VBlank.

Actually, the numbers I've given are (a) probably wrong, and (b) for pulling from a giant uncompressed map in ROM, which is not how F-Zero works. I imagine a hack could work that way in principle, with a massive ROM expansion, but even then you're pulling non-contiguous 64-byte pieces and concatenating them, which is a lot of DMA transfers, meaning a lot of overhead. It would require some extra code for DMAing across bank boundaries (indexing works, but DMA wraps) that would increase the overhead a little beyond what I've suggested above. I still think it could probably be forced to work on a stock SNES, but an enhancement chip would help quite a bit.

I should probably study up on how F-Zero builds its maps before I get too much farther along on this topic...
Re: 2 Player F-Zero Feasibily
by on (#179409)
Hey all, just wanted to post some information on F-Zero VS, the server-based multiplayer version of SNES F-Zero. Basically what FZVS is for those who don't know is a 4-player multiplayer version of SNES F-Zero that uses a modified version of snes9x to allow people to connect via a server. The author of it stated,
Quote:
"During the emulation process, many patches to the ROM are made to turn various aspects of the the gameplay into multiplayer, while several memory hooks watch the RAM for certain signals that indicate different game states etc."
You can read more about that exact process as this page (http://fzerovs.blogspot.com/2008/07/what-is-fzvs.html) at the FZVS blog (long abandoned).

The author got asked a lot if this could work on real hardware, either with an XBAND or via a link cable between systems. He said it was definitely possible, his code would just have to be tinkered with a little. Good news is that he uploaded the source code of the project (in two parts, the snes9x code and the server code) at his blog: http://fzerovs.blogspot.com/2009/06/f-zero-vs-source-code.html

Bad news is the link to the source code download no longer works and I can't find a working link anywhere across the internet. None of the previous links work in archive.org either. Basically this source code is lost. The only other thing I've thought of trying is sending emails to the commenters on the source code page who did indeed download it and see if they still have it and can upload it somewhere like github or something (however, a lot of them, don't look active anymore). I also found a blog that linked to the source code, but that person hasn't wrote a article on the blog in years so who knows if they would respond to an email.

I wouldn't be able to work on this even if I had the source code, but I'd like the information out there for anyone in the future who would ever want to give it a try. This seems to me to be a good project for the SNESoIP team to work on (ttp://www.retrocollect.com/News/snesoip ... tendo.html) or to get working on real hardware via link cable. I found an old thread on the old version on romhacking.org via archive.org that discusses the feasibility of making a link cable. https://web.archive.org/web/20100327182800/http://www.romhacking.net/forum/index.php/topic,6893.0.html
Here's what the author had to say,
Quote:
"It wouldn't require a lot of code modification, although I'd need to do some things differently. I'd need to inject some code into the main loop to do what the emulator essentially does (updating the RAM etc). But I also patch the ROM in realtime, so in these cases I'd probably need to substitute it with different approach. All possible of course."

User neviksti wrote about the possibility of making a joyport link cable (sorry this is a lot of text, can't find spoiler tags?),
Quote:
"Also, with the joyport link cable, you wouldn't have to worry about latency issues.

fzvs, how are you currently dealing with latency issues? (also, what about other synchronizing issues ... like if a car explodes?)

Anyway, here are the cable details:

SNES controller connector:
rounded tip
GND
IO
D1
separator
D0
latch
clk
Vcc
square end

The SNES can read the values on IO,D0,D1.
Clk is an output from the SNES that is pulsed when reading certain SNES hardware registers.
The SNES can output values on IO and latch.

Unfortunately, all the SNES "extender" cables I've found on Ebay actually only work for controllers (not the guns, etc.). That is because they are cheap and only pass through Gnd,Vcc, Clk,latch,D0.

So the very simplest design would be take two of these extenders and:
GND <-> GND
D0 <- latch
latch -> D0

The problem with this is there is no easy way to know when the next bit is ready. Carefully written code can make this work though.


If all lines pass through (buy two of those cheap TribalTaps and gut them for the cable connectors):
GND <--> GND
D0 <- latch
D1 <- IO
latch -> D0
IO -> D1

Or, you could even make it asymmetric so the snes can detect which side it is, and use this to automatically select one machine as "player 1". You can either use careful code and send twice as much now, or use one of the data lines to indicate when the next bit is ready (easier to code and debug).


If the first way works, that is clearly preferable, as it would be the easiest and cheapest for anyone to make. Also, the extenders are usually 6 foot, so after splicing two to make the cable it would be 12 foot ... which would be a decent distance for setting up the two systems. You could instead make the SNES connectors attach to phone line connectors (most phone lines have at least 4 wires internally)... then you could string a long phone line to set the distance however you want."


I know some people want to work on a split screen version of F-Zero, but I think a link cable version would be great too and wouldn't lessen the gameplay by having less view-able driving area on the screen. The author of FZVS only ever made it v1.1 before he disappeared. In v1.2, he was going to correct the cars crash behavior (in the original game your momentum is transferred to the car you hit). He was also working on a never released program that looked at debugging SNES games in an unusual, but interesting way: SNES Code Visualizer. Below I will post a bunch of code that the original F-Zero author posted on his blog so that in case it ever disappears off his site it will still be on this thread; hopefully it can be useful to someone in the future who would ever want to work on this:

Quote:
Now I will explain exactly what happens inside the SNES emulator when you load the ROM (only the ROM specific stuff needs to be mentioned):

1) To disable any menu selections at the title screen other than the first option, patch 03:8176 INC to NOP:
Memory.ROM[(0x8000*3)+0x0176] = 0xEA;

2) To disable the 'demo race' at title screen (as this will trigger game states we don't need), patch 03:8143 BNE $8148 to BRA $8148:
Memory.ROM[(0x8000*3)+0x0143] = 0x80;

3) Then we wait for the player to select a car. To catch car selection, check memory status at $7E:0055. When it equals 0x03 we know a car has been selected. You can determine which car was selected by reading $7E:005A at this point. The order (from 0-3) is bf (blue falcon), gf (golden fox), wg (wild goose), fs (fire stingray). This is a different representation to what is used internally in the F-Zero ROM, where it is bf, wg, gf, fs. So I change the returned value to suit that.

4) We should not proceed to the game until all players have entered their car selections. So, we wait for the game to start transitioning to the next screen, breaking when $7E:0055 == 0x05. When this condition is met, we halt the screen progression until we receive notification from the server that everyone is ready. In order to pause the game while keeping the music playing etc, we patch the ROM 03/851F: A5 55 F0 74 LDA $55 to become 5C 1F 85 03 JMP 03851F.
Memory.ROM[(0x8000*3)+0x051F] = 0x5C;
Memory.ROM[(0x8000*3)+0x0520] = 0x1F;
Memory.ROM[(0x8000*3)+0x0521] = 0x85;
Memory.ROM[(0x8000*3)+0x0522] = 0x03;

5) We only continue when we have received notification from the server that all the players have selected their cars. Furthermore the server will have sent other data such as the track to race on, player id, number of players in the race etc.

6) Then we set the car types based on the data received from the server. The player previously received from the server a player id, this is a unique value from 0 to 3. It determines the players position in the starting line from left to right.

So, let's assume we are the first player to log on to the server, making our player id == 0. This means, our car will be in the fs position on the starting line, on the far left. However, let's assume we chose bf as our car.

We need to change the viewpoint of the car to match the fs location. To do this, we patch 00:D2EF A5 52 LDA $52 to A9 0x LDA #$x where x is a value from the internal representation of the car selection (being bf, wg, gf, fs):
Memory.ROM[0xD2EF-0x8000] = 0xA9;
Memory.ROM[0xD2F0-0x8000] = x;

To set the player car palette to be based on the player id, patch 00:D72B LDA $52 to LDA #$pid where pid is the player id:
Memory.ROM[0xD72B-0x8000] = 0xA9;
Memory.ROM[0xD72C-0x8000] = pid;

Then we can set the opponent car types, based on the data we received earlier. To do this, we write to RAM:
Memory.RAM[0x1133] = x;
Memory.RAM[0x1135] = y;
Memory.RAM[0x1137] = z;

where x, y and z are the player car types from right to left on the starting line, excluding the player id's location. So in our example of having player id == 0, with the starting line order being (fs, bf, wg, gf) the code would be:
Memory.RAM[0x1133] = player who is in the gf position;
Memory.RAM[0x1135] = player who is in the wg position;
Memory.RAM[0x1137] = player who is in the bf position;

Then we can set the colours of the opponent cars. Our aim is to make sure that the first car is always pink, second is always blue, third is green and fourth is yellow - no matter what car type is selected. We write to RAM at 0x0C41, 0x0C43, 0x0C45, 0x0C47 where 0x0C41 is the player car's colour, and the 0x0C43/5/7 are the colours of the opponents based on the player id. So, if we are in player id position 0:
Memory.RAM[0x0C41] = 0x0E;
Memory.RAM[0x0C43] = 0x08;
Memory.RAM[0x0C45] = 0x0A;
Memory.RAM[0x0C47] = 0x0C;

Finally we then make a few small patches that are needed to make things run smoothly. We patch the code at 00:D486 LDX #$00 to JMP $D4A7, to skip the car loop iteration:
Memory.ROM[0xD486-0x8000] = 0x4C;
Memory.ROM[0xD487-0x8000] = 0xA7;
Memory.ROM[0xD488-0x8000] = 0xD4;

we patch the code at 00:D32B STA $1131,X to NOPs, to make sure the car types are never overwritten:
Memory.ROM[0xD32B-0x8000] = 0xEA;
Memory.ROM[0xD32C-0x8000] = 0xEA;
Memory.ROM[0xD32D-0x8000] = 0xEA;

and to stop the player car palette from defaulting back to the original when it crosses the finish line, patch 00:8DB6 JSR $C782 to NOPs:
Memory.ROM[0x8DB6 - 0x8000] = 0xEA;
Memory.ROM[0x8DB7 - 0x8000] = 0xEA;
Memory.ROM[0x8DB8 - 0x8000] = 0xEA;

8) Now I need to explain how the F-Zero game actually works.

F-Zero tracks the progress of five displayed cars. The locations of these cars are stored at: 7E:0B70-0B79 (x values) and 7E:0B90-0B99 (y values). Since each race has something like 20 cars or more, there are many cars on the track whose locations are unaccounted for at any one time. When these cars need to be displayed, the game 'places' them on the track where it thinks they should be, based on a checkpoint system, rather than actually racing them around the track properly. This was probably done due to SNES system constraints, but discovering this answered a lot of questions for me. Ever wonder why there was always a car right behind you, no matter how well you were driving? Now you know :)

What this means, is we need to make a few more modifications.

We need to get rid of the annoying opponent 'catch up' code. As I stated above, the game often decides when a car is about to over take you. It's not like the cars are always racing around the track in a linear fashion. The game may decide to make a car jump from really far away, to just behind you, simply because you are playing poorly. We can't have random 'check' warning messages in our multiplayer races either.

We also need to get rid of all the generic enemy cars, these are the ones that have the boring racing stripe and never win the races. If we don't do this, the code will just keep introducing them in to the game everytime we crash in to the wall a few times.

The good news is we can solve both problems simply. We patch 00:DDFC JSR $DED0 to EA NOP * 3:
Memory.ROM[0xDDFC - 0x8000] = 0xEA;
Memory.ROM[0xDDFD - 0x8000] = 0xEA;
Memory.ROM[0xDDFE - 0x8000] = 0xEA;

9) Next we have to stop the opponent AI from working, while still allowing the cars movement. If we don't do this, then the car will have jagged motion around the track as it is receiving contradicting movement commands from the server and the AI. So, we patch 00:DDDA JSR $DE57 to EA NOP * 3:
Memory.ROM[0xDDDA - 0x8000] = 0xEA;
Memory.ROM[0xDDDB - 0x8000] = 0xEA;
Memory.ROM[0xDDDC - 0x8000] = 0xEA;

10) Now another thing you will notice is that when the race first starts, even though you have disabled the opponents AI, they still boost off the finish line (before slowing to a halt). If we don't stop this boost, the car will have the same jagged motion described earlier at the start of the race. So we patch 00:8D3E LDA #$02 to LDA #$00:
Memory.ROM[0x8D3F - 0x8000] = 0x00;

11) The race relies on synchronization, and if a player accidentally pauses the game they will break the synchronization. So we disable pausing by patching 00:C8FF F0 06 BEQ $C907 to be 80 06 BRA $C907:
Memory.ROM[0xC8FF - 0x8000] = 0x80;

12) Now we must make sure that when the race is complete, the game does not proceed beyond the race time summary screen until it receives notification from the server that all players have finished. We patch 00:CD84 90 03 BCC $CD89 to be 80 03 BRA $CD89:
Memory.ROM[0xCD84 - 0x8000] = 0x80;

13) And finally, we can resume execution of the ROM (from point 4 above) meaning the game will progress beyond the car select screen to the league selection:
Memory.ROM[(0x8000*3)+0x051F] = 0xA5;
Memory.ROM[(0x8000*3)+0x0520] = 0x55;
Memory.ROM[(0x8000*3)+0x0521] = 0xF0;
Memory.ROM[(0x8000*3)+0x0522] = 0x74;

14) We skip the league and difficulty selection because it is already chosen for us by the server. I do this crudely by patching 03/8795: B0 35 BCS $87CC to BRA $87CC 80 35:
Memory.ROM[(0x8000*3)+0x0795] = 0x80;

and by patching 03/87E6: 6B RTL to be another INC $55 (this makes it 7, to start the race). Note this pushes the RTL into the 'class' select code but that code is not used anyway:
Memory.ROM[(0x8000*3)+0x07E6] = 0xE6;
Memory.ROM[(0x8000*3)+0x07E7] = 0x55;
Memory.ROM[(0x8000*3)+0x07E8] = 0x6B;

15) We instead set the league and the track number by patching the RAM at 7E:0053 (track number) and 7E:005A (league number).
Memory.RAM[0x53] = track_num;
Memory.RAM[0x5A] = league_num;

16) By this stage the game is preparing to start the race. All players need to send their location and orientation to the server before the race starts, otherwise the opponent cars will temporarily disappear as the server has not been told where they are. We wait for the locations to be loaded by breaking when 7E:0054 == 2, 7E:0055 == 0 and 7E:0056 == 2:
if((Memory.RAM[0x54] == 0x02) && (Memory.RAM[0x55] == 0x00) && (Memory.RAM[0x56] == 0x02))

then we read the 16 bit value at 7E:0B70 (this means also 7E:0B71) to get the x value, and similarly 7E:0B90/1 for the y value. The car's orientation is at 7E:0BD1.

17) Once the server has received all the data required, it can instruct the clients to start the race. Each emulator must now send the player's location to the server, while receiving and updating the opponents locations from the server as fast as possible. It should be obvious that the opponent x and y location values are stored in RAM at 7E:0B72/3,7E:0B74/5, 7E:0B76/7 and 7E:0B92/3,7E:0B94/5, 7E:0B96/7. Similarly the opponent orientation data is at 7E:0BD3, 7E:0BD5 and 7E:0BD7 where the order is based on the player id.

18) We want to be able to tell the server when our player has finished the race, either by crossing the finish line or destroying the car. So we watch the RAM at 7E:0054 until it equals 3:
if(Memory.RAM[0x54] == 0x03) game_state = GAMESTATE_RACEFINISHED;

19) And there is just one tiny other detail. There is a fifth car. Remember above, I said the AI controls 5 cars at any one time? Well this fifth car is a generic car and we need to remove it. I do it the laziest way possible, I just constantly reset it's location to zero every vsync.
Memory.RAM[0x0B78] = 0;
Memory.RAM[0x0B79] = 0;
Memory.RAM[0x0B98] = 0;
Memory.RAM[0x0B99] = 0;

............................................................

Car collisions will not work properly until we make a few modifications. When a collision between two cars occurs, both emulator instances involved try to control both car rebound velocities. This conflict results in jagged movement.

The solution to this is to:

a) Make sure that each emulator instance only rebounds its own player during a player-opponent collision by patching occurrences of the code 99 20 0B STA $0B20,Y to NOPs at ROM addresses 00:BDB2, 00:BDD5, 00:BDEF and 00:BDFE.

b) Make the player's rebound speed equal to his current speed instead of the opponents speed (which is what happens in the game) by patching occurrences of the code 9D 20 0B STA $0B20,X to NOPs at ROM addresses 00:BDAE, 00:BDCB and 00:BDE5.


Also, looks like he was maybe working on a disassembly of the game (or just research for FZVS): http://1.bp.blogspot.com/_l9KpEMvIEik/Swx1v8lXPQI/AAAAAAAAAME/j5dhcG7e9aQ/s1600/tools.jpg
Re: 2 Player F-Zero Feasibily
by on (#179439)
The author of FZVS is a member here: mikeyz
Re: 2 Player F-Zero Feasibily
by on (#179544)
Unfortunately he joined over 7 years ago and only posted three times. Doesn't even show when his last visit was since it was so long ago.
Re: 2 Player F-Zero Feasibily
by on (#179554)
suFami wrote:
Unfortunately he joined over 7 years ago and only posted three times. Doesn't even show when his last visit was since it was so long ago.

Not necessarily. The "don't show others your online status" checkbox also prevents a logging of a "last visit" (see: my profile)
Re: 2 Player F-Zero Feasibily
by on (#182795)
suFami wrote:
4-player multiplayer
Quote:
lessen the gameplay by having less view-able driving area on the screen

I was thinking that if you could get 8 KB of map data decompressed and concatenated in one frame without crowding out the rest of the game engine, you could do a 4-player split-screen F-Zero on SNES.

Unfortunately, the task is probably utterly impossible on the S-CPU, not least because you'd need a big ugly H-IRQ to handle the Mode 7 matrix split. This implies the SA-1, or possibly the Super FX, and it happens that both of those chips draw too much current to be used together with a multitap.

More importantly, I'm pretty sure it's impossible on the S-PPU regardless, since only half the matrix is reapplied every pixel, so you can't do arbitrary rotation changes mid-scanline...

Oh well... it was kinda ugly anyway...
Re: 2 Player F-Zero Feasibily
by on (#182905)
Looks good, too bad you're saying it can't work. If you need any info definitely check out CatadorDeLatas's F-zero Notes Document: https://docs.google.com/document/d/1yhZrwn7Mq8WL83YWzSFIKB4mHWEC84TXpvRU2_Pb7lE/edit?usp=sharing.
He's done a lot of work to map out pretty much the whole game. Tons of RAM and ROM addresses with explanations. I'd say right now CatadorDeLatas knows the inner workings of SNES F-Zero more than anyone else besides the original developers.

He's mostly active in this F-Zero thread on SMWCentral: https://www.smwcentral.net/?p=viewthread&t=85909
He's made patches that make the CPU cars explode if they fall off the track and even gave them health like the player has (!).
Here's a link to a work in progress document he's making on F-Zero's SPC engine: https://docs.google.com/document/d/1IelzfB72b51cj9AqjFCb8Gg235ismuKsrgmmw5c7i5Q/edit Maybe KungFuKirby could be of some help? Here's what he said about it in the thread,
Quote:
"I tried modifying EBMusEd (Earthbound Music Editor) to work but I couldn't actually do it. Mainly because EB is HiRom and FZ is LoRom, this screws SNES address to PC address conversion."

He's also made three useful LUA scripts (Checkpoint, Track, and Car info):
Image
Image
Image
Re: 2 Player F-Zero Feasibily
by on (#183101)
Yup, I fooled around with this game back in 2012.

All I did with F-Zero was to give it the ability to pick any of the course music to race with (which for me acts as a bank modifier). nensondubois produced the sub-tune portion of the music modifier, and what I produced only works at the start of a race if memory serves me right.

Here's the music modifier, combining nensondubois's original code and my bank modifier (for the US version):
(Sub-tune)
7E0046xx
(Bank ID at start of race)
80F7E3A2
80F7E400
80F7E5EA
839E68xx
The music modifier by nensondubois supports 01-08, wrapping around at 08. The bank modifier, which only affects sub-tune tune 06, supports 00-09. By default, bank 07 is the one that's loaded. The game crashes after bank 09.
Re: 2 Player F-Zero Feasibily
by on (#183524)
suFami wrote:
Looks good, too bad you're saying it can't work.

I believe the fake screenshot I posted is possible on a real SNES, but it would glitch out the moment anybody tried to steer... I could try it, I suppose, but given what happened when I tried switching from Mode 1 to Mode 7 mid-scanline, I don't expect a happy result. And the power supply constraint means there's not much point in trying anyway.

Quote:
If you need any info definitely check out CatadorDeLatas's F-zero Notes Document: https://docs.google.com/document/d/1yhZrwn7Mq8WL83YWzSFIKB4mHWEC84TXpvRU2_Pb7lE/edit?usp=sharing.
He's done a lot of work to map out pretty much the whole game. Tons of RAM and ROM addresses with explanations. I'd say right now CatadorDeLatas knows the inner workings of SNES F-Zero more than anyone else besides the original developers.

He's mostly active in this F-Zero thread on SMWCentral: https://www.smwcentral.net/?p=viewthread&t=85909
He's made patches that make the CPU cars explode if they fall off the track and even gave them health like the player has (!).

Very interesting stuff.

I don't expect to be working on F-Zero myself any time soon, as the shmup port I'm working on is almost stalled (as are all of my other hobbies) due to the requirements of real life. But I can throw together a mockup in Paint/GIMP pretty easily when the mood strikes me...

Attachment:
f-zero_2player.png
f-zero_2player.png [ 282.53 KiB | Viewed 5127 times ]

I'm assuming here that the SA-1 is powerful enough to decompress 4 KB of map data per frame (as discussed earlier in the thread) and render an 8-line-high strip of 2bpp software Mode 7 for each player right above the actual Mode 7 horizon, so as to let the players see further ahead and mitigate the visibility issues with the compressed perspective. This trick would also allow for faster speeds in the hypothetical SA-1-based F-Zero X prequel I like to daydream about - GP Legend features X-class speeds with SNES-style graphics, and I find it too fast for the draw distance...
Re: 2 Player F-Zero Feasibily
by on (#212746)
Just wanted to post that the creator of FZVS has re-uploaded the source code (after 9 years!):
http://fzerovs.blogspot.com/2009/06/f-zero-vs-source-code.html
Here's the dropbox link: https://www.dropbox.com/s/id7afnv12i9yprn/source%20release%2012.06.09.rar?dl=0