tag:blogger.com,1999:blog-69112582643122984912024-03-19T03:15:46.865-07:00F-Zero VSsydney, australiaUnknownnoreply@blogger.comBlogger11125tag:blogger.com,1999:blog-6911258264312298491.post-49160279988040527332009-12-03T21:57:00.000-08:002009-12-04T12:34:35.534-08:00SCV - SNES Code Visualiser<div style="font-family: Verdana,sans-serif;">Hello fellow SNES lovers, this post is to discuss my SNES Code Visualiser, otherwise know as SCV. This code was hacked together very quickly, just to show an idea - it's not a finished product and I'd love to hear suggestions for improvements.<br />
</div><div style="font-family: Verdana,sans-serif;"><br />
</div><div style="font-family: Verdana,sans-serif;">Basically I started thinking about what it would be like to plot the CPU program counter. I figured it would look like a 'pulse', and I even had a cool name for it, I called it the program counter pulse. In slow motion, I imagined seeing the PC going across the screen, following the same paths again and again. And occasionally new paths would be seen as player input forced different branch and jump logic to become true.<br />
</div><div style="font-family: Verdana,sans-serif;"><br />
</div><div style="font-family: Verdana,sans-serif;">It was that point that stuck to me. What if we could visually identify specific code, as it happens?<br />
</div><div style="font-family: Verdana,sans-serif;"><br />
</div><div style="font-family: Verdana,sans-serif;">The way I have achieved this is by taking advantage of the small ROM page size of the SNES. 16-bit addressing means page size is limited to 2^15 bytes when loROM is being used and 2^16 bytes with hiROM. If you assume the worst case scenario of hiROM, you can actually visually represent every single byte on the page in a neat 256 x 256 pixel square (256*256=2^16)!<br />
</div><div style="font-family: Verdana,sans-serif;"><br />
</div><div style="font-family: Verdana,sans-serif;">To show you how effective this can be, I'm going to run you through an example usage, to find some really arcane code. Since F-Zero is my favourite, let's find the code that is executed everytime a car jumps onto and over a ramp.<br />
</div><div style="font-family: Verdana,sans-serif;"><br />
</div><div style="font-family: Verdana,sans-serif;">Now keep in mind, the old way this would have worked is probably by tracing through the ROM over a couple of days, writing comments on a disassembled listing of the ROM, until you grasp the mechanics of the program enough to isolate events like jumping on a ramp. With this debugger, you can isolate the code in less than one minute. <br />
</div><div style="font-family: Verdana,sans-serif;"><br />
</div><div style="font-family: Verdana,sans-serif;">Here's how: you start the ROM up<br />
</div><div style="font-family: Verdana,sans-serif;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhf-ComUI9evyAYi8e3CUgydd-EM_2TdxQN5ZVd07024wl4jQUUmfN-18Hul37DrGlcvbvzZhbyToNCXJ6-UzgHsY5t15y3-OzxRgg7Z55QuJ3KNEtMorPf4x4mFlSXLRaCjEpuolQQAk/s1600-h/fz1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhf-ComUI9evyAYi8e3CUgydd-EM_2TdxQN5ZVd07024wl4jQUUmfN-18Hul37DrGlcvbvzZhbyToNCXJ6-UzgHsY5t15y3-OzxRgg7Z55QuJ3KNEtMorPf4x4mFlSXLRaCjEpuolQQAk/s400/fz1.jpg" /></a><br />
</div><div style="font-family: Verdana,sans-serif;"><br />
</div><div style="font-family: Verdana,sans-serif;"><br />
</div><div style="font-family: Verdana,sans-serif;">and get past the title screen, choose 'practice mode' so no other cars are bothering you, choose your car, league etc, and you'll notice as you progress further in to the game, more and more red pixels are lighting up on the screen immediately to your right. So keep going until you get to the race screen.<br />
</div><div style="font-family: Verdana,sans-serif;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5zDlGg04ygDOZKCggls8B3BBRwP7GTUTxDF8l6yCTxoxYEIcqBrdfAyl46tayQEm5GdP91RnxNiKrS36N_73vbdDDBuxCi6OPGQTrLaCrvnnzx5r41i8w7I2nCPV_1LXIxxXr9kCJTTI/s1600-h/fz2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5zDlGg04ygDOZKCggls8B3BBRwP7GTUTxDF8l6yCTxoxYEIcqBrdfAyl46tayQEm5GdP91RnxNiKrS36N_73vbdDDBuxCi6OPGQTrLaCrvnnzx5r41i8w7I2nCPV_1LXIxxXr9kCJTTI/s400/fz2.jpg" /></a><br />
</div><div style="font-family: Verdana,sans-serif;"><br />
</div><div style="font-family: Verdana,sans-serif;"><br />
</div><div style="font-family: Verdana,sans-serif;">Now suddenly it's like a fireworks display, many many more pixels are turning red. Each of these pixels, gentlemen, is the representation of an instruction that has been executed in the ROM. In this case, you are looking at bank 0, but you can change the bank by pressing page up or down. Of course, tracking is done on all pages simultaneously, so you never miss anything.<br />
</div><div style="font-family: Verdana,sans-serif;"><br />
</div><div style="font-family: Verdana,sans-serif;"><br />
</div><div style="font-family: Verdana,sans-serif;">So you start the race, and drive around a bit. Collide in to a wall. More red pixels suddenly light up. Is there any doubt these pixels represent the code that deals with collisions? Nonetheless, as more and more pixels are triggered, it's getting a bit hard to differentiate what code is what. Actually this plays to our advantage, because the more pixels that turn red, the more code you have identified as not being part of the ramp jumping routine.<br />
</div><div style="font-family: Verdana,sans-serif;"><br />
</div><div style="font-family: Verdana,sans-serif;"><br />
</div><div style="font-family: Verdana,sans-serif;">Eventually, no more pixels are turning red. You are ready. Proceed to the ramp, rev your engines.<br />
</div><div style="font-family: Verdana,sans-serif;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgicwYs0mLH91eEfvcj07IzVfWs7UyRr_5IQNAhezAWPz6DbJ3SVIiYKQMKltRWs_6vLf-Ew2NrL8SlScTicmtL9I7rDwqXAn_3cugn2wNFFMVQ0p6h1Z_mw_2U7d4u7lO8RAywWAvJCN0/s1600-h/fz3.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgicwYs0mLH91eEfvcj07IzVfWs7UyRr_5IQNAhezAWPz6DbJ3SVIiYKQMKltRWs_6vLf-Ew2NrL8SlScTicmtL9I7rDwqXAn_3cugn2wNFFMVQ0p6h1Z_mw_2U7d4u7lO8RAywWAvJCN0/s400/fz3.jpg" /></a><br />
</div><div style="font-family: Verdana,sans-serif;"><br />
</div><div style="font-family: Verdana,sans-serif;"><br />
</div><div style="font-family: Verdana,sans-serif;">Press the 'end' key to change the color of any new pixels to green, and fly over the ramp. Immediately you see a bunch of suspicious green pixels. The tool immediately disassembles all the green pixels in to assembly language. But it's not just a disassembly - what you are now seeing on the screen is an actual trace of the code that occurred in the past, starting with the last red pixel to be run before the green pixels started. This first instruction in the trace, the red pixel which calls the first green pixel, is our testing branch.<br />
</div><div style="font-family: Verdana,sans-serif;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjq7AS35DqIRhhWjQzYT9VASl6cNtdqNuTGPmTtlKRrdNbJS30wGl28D8RYERQSwJ_sdA2FaVlIP-glpjw02Dzn2dD-zBZuYbM8cCWRgNA7kP-D3XnFL57uCCEIaVDGDdvnsKEFMF8w3NI/s1600-h/fz4.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjq7AS35DqIRhhWjQzYT9VASl6cNtdqNuTGPmTtlKRrdNbJS30wGl28D8RYERQSwJ_sdA2FaVlIP-glpjw02Dzn2dD-zBZuYbM8cCWRgNA7kP-D3XnFL57uCCEIaVDGDdvnsKEFMF8w3NI/s400/fz4.jpg" /></a><br />
</div><div style="font-family: Verdana,sans-serif;"><br />
</div><div style="font-family: Verdana,sans-serif;">If you press page down, you can see ROM bank 3's pixels, including a few tiny green ones. The white pixel (it's hard to see) is the highlighted ASM instruction on the right (aka. the branch).<br />
</div><div style="font-family: Verdana,sans-serif;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_5Ha1t79ew8_-R1LGaxR6bd9wtpVxBewmYKcEJJn-_l0mVwuu9lN_qgvz-JQMChEyuOejEiIsNV2IYpwbAgWYMORjJEKbcOVIxLbDplHygT79r6n0_60XnG9BEvGw8_00BQj-_6BtGk0/s1600-h/fz5.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_5Ha1t79ew8_-R1LGaxR6bd9wtpVxBewmYKcEJJn-_l0mVwuu9lN_qgvz-JQMChEyuOejEiIsNV2IYpwbAgWYMORjJEKbcOVIxLbDplHygT79r6n0_60XnG9BEvGw8_00BQj-_6BtGk0/s400/fz5.jpg" /></a><br />
</div><div style="font-family: Verdana,sans-serif;"><br />
</div><div style="font-family: Verdana,sans-serif;"><br />
</div><div style="font-family: Verdana,sans-serif;">For fun, let's NOP it. Select the instruction and press 'N'. This replaces the two bytes that make up the branch instruction with 0xEA, 0xEA. Now restart the ROM, and try to jump over the ramp. You can't. Congratulations you have just delved deep inside a SNES ROM and made a change in about 1 minute. That is the power of this tool.<br />
</div>Unknownnoreply@blogger.com5tag:blogger.com,1999:blog-6911258264312298491.post-3794507102635834862009-11-24T16:22:00.000-08:002009-12-06T00:02:42.396-08:00A New Graphical Reverse Engineering Tool<div style="font-family: Verdana,sans-serif; text-align: justify;">When I was working on F-Zero VS, I took a screenshot of my desktop to remember my work environment:<br />
<br />
</div><div class="separator" style="clear: both; font-family: Verdana,sans-serif; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLumLT-KAiYkmPT9PM81vTYUS8w-NGa8R8bZp-UEBnTREMnSExbrvX1iVW3dwYNv9LzXoBQ5_esF0oHOi71LDqCNzHmCHqD8U1JcXUvrXQM8ShK56a7SjAB_v4AIAJod162JXXGWNeac0/s1600/tools.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLumLT-KAiYkmPT9PM81vTYUS8w-NGa8R8bZp-UEBnTREMnSExbrvX1iVW3dwYNv9LzXoBQ5_esF0oHOi71LDqCNzHmCHqD8U1JcXUvrXQM8ShK56a7SjAB_v4AIAJod162JXXGWNeac0/s400/tools.jpg" /></a><br />
</div><div style="font-family: Verdana,sans-serif; text-align: justify;"><br />
</div><div style="font-family: Verdana,sans-serif; text-align: justify;">Pictured: Snes9x with Geiger's debugger mod, and Notepad with TRaCER output.<br />
<br />
When it comes to reverse engineering SNES ROMs, this is pretty much the "state-of-the-art", given the tools available are scarce. While reverse engineering work is enjoyable, its also tedious, inefficient and slow.<br />
</div><div style="font-family: Verdana,sans-serif; text-align: justify;"><br />
</div><div style="font-family: Verdana,sans-serif; text-align: justify;">I have been contacted by many people asking me to do various hacks, including converting many different games to multiplayer. I really would love to help but finding the time seems impossible for me. If only there was a faster way... I love reverse engineering for all platforms, not just SNES, and want to see new developments in this field. I am thinking of writing a SNES tool that shows code execution graphically, also allowing you to quickly isolate code sections.<br />
</div>Unknownnoreply@blogger.com4tag:blogger.com,1999:blog-6911258264312298491.post-84480192834012796222009-06-12T05:10:00.000-07:002010-04-13T18:20:12.094-07:00F-Zero VS Source Code<div style="text-align: left;"><span class="Apple-style-span" style="font-family: verdana;"><span class="Apple-style-span" style="font-size: small;">I have released the source code (I know I should have done this earlier) as people have been requesting it to make their own modifications and improvements.</span></span><br />
<br />
<span class="Apple-style-span" style="font-family: verdana;"><span class="Apple-style-span" style="font-size: small;">You are free to make any modifications you wish to the code. Let me know if you make any changes and I will post the updates on this site.</span></span><span class="Apple-style-span" style="font-family: verdana;"><br />
<br />
</span><span class="Apple-style-span" style="font-size: small;"><span class="Apple-style-span" style="font-family: verdana;">Here's the code: <a href="http://www.megaupload.com/?d=VYL5SA35">http://www.megaupload.com/?d=VYL5SA35</a></span></span><span class="Apple-style-span" style="font-family: verdana;"> Contact me if you want the source and the files are not there anymore.</span><br />
<br />
<span style="font-family: verdana;">Note: The source comes in two parts, the snes9x emulator code and the server code. The Snes9x code is compiled with MS Visual C++ 6.0. The server code is compiled with Visual C# Express 2008 which is a free download from Microsoft's website.</span></div>Unknownnoreply@blogger.com17tag:blogger.com,1999:blog-6911258264312298491.post-42728551767995856612009-01-16T03:50:00.000-08:002009-02-26T12:52:54.722-08:00F-Zero VS v1.1 release<p><span style="font-family:verdana;">So far no bugs have been reported, which is a good sign.</span></p><p><span style="font-family:verdana;">However I have decided to release v1.1, which is just a very minor update. The only change since v1.0 is that a ROM check now occurs when you first start. This ROM check basically warns you if you do not have the correct version of the ROM (just a checksum comparison). Remember the correct version is 'F-Zero (U) [!].smc'.</span></p><p><span style="font-family:verdana;">You can choose to ignore this warning if you know you are using a hacked ROM (with new tracks for example) and are confident it will work. But if it doesn't, it means the code FZVS is supposed to be patching is not at the right locations.</span><br><br /><span style="font-family:verdana;"><a href="http://www.zophar.net/snes/fzvs.html">http://www.zophar.net/snes/fzvs.html<br /></a></span></p><p><s><a href="http://www.filesavr.com/fzvsv11"><span style="font-family:verdana;">http://www.filesavr.com/fzvsv11</s></span></a></p>Unknownnoreply@blogger.com45tag:blogger.com,1999:blog-6911258264312298491.post-71895775985070345762009-01-04T21:38:00.000-08:002009-01-18T20:25:36.733-08:00F-Zero VS v1.0 release<span style="font-family:verdana;">Hello again,</span><br /><br /><span style="font-family:verdana;">Over the Christmas break I got to working on the code again after a long break and now finally, I have released v1.0.</span><br /><br /><span style="font-family:Verdana;">You probably need the .NET Framework installed on your PC to run the server (you should have it installed anyway).</span><br /><br /><span style="font-family:Verdana;">Get the package here: <a href="http://www.filesavr.com/fzvsv10_1">http://www.filesavr.com/fzvsv10_1</a></span><br /><br /><span style="font-family:Verdana;">How to use it:</span><br /><br /><span style="font-family:Verdana;">1) First, load FZVS_Server.exe. Specify the UDP port number you want to listen on, and hit the 'listen' button. Then select the number of players for the race and the track name, and press 'new race'.</span><br /><span style="font-family:Verdana;"></span><br /><span style="font-family:Verdana;">2) You need to have the F-Zero ROM, which I cannot include in the package (obviously). There are many versions and I'm assuming that they all work, but if you notice the game not working properly, use the GoodSNES ROM version, which is called 'F-Zero (U) [!].smc'. This file should be in the same directory as the .exe files.</span><br /><br /><span style="font-family:Verdana;">3) Start FZVS_Client.exe. Specify the IP address and port number the server is listening on (see point 1 above) and press OK. The game should start. Choose a car.</span><br /><span style="font-family:Verdana;"></span><br /><span style="font-family:Verdana;">4) Repeat step 3, but run the FZVS_client.exe on other computers across the network or even on the same PC (if you have two gamepads on the one PC for example).</span><br /><span style="font-family:Verdana;"></span><br /><span style="font-family:Verdana;">5) Race!</span><br /><span style="font-family:Verdana;"></span><br /><span style="font-family:Verdana;">6) When all racers have finished, stop the race on the server by pressing 'Stop Race'. The FZVS clients should return to the main menu automatically. Then you can press 'New Race' again and select cars etc... make sure you press the new race button BEFORE you select the cars.</span><br /><span style="font-family:Verdana;"></span><br /><span style="font-family:Verdana;">I recommend you play through a local network to minimise latency.</span><br /><span style="font-family:Verdana;"></span><br /><span style="font-family:Verdana;">Another option is to run multiple clients on the same PC. My Intel Quad Core Q6600 @ 2.40GHz PC can handle four clients running on it at once through localhost (127.0.0.1) with ease... with four game pads and a big screen this is a good option.</span><br /><span style="font-family:Verdana;"></span><br /><br /><br /><p><span style="font-family:Verdana;">Another note: if you have a multiple players in one room you probably don't want each FZVS client playing the music as this will result in multiple versions of the same song being played (ever so slightly out of sync). I added an option under Sound->Toggle Music which will disable music but leave the race sound effects etc enabled.</span></p><span style="font-family:Verdana;">Finally: once the race starts you should not access the menu bar or move/resize the window. In these cases the game will pause and lose sync with the other players. It's not that big of a deal but it will cause the race timers to be out of sync, which may matter to some people.</span>Unknownnoreply@blogger.com12tag:blogger.com,1999:blog-6911258264312298491.post-58828855590620534922008-10-19T21:01:00.000-07:002009-01-05T04:11:58.673-08:00Excuses...<span class="Apple-style-span" style="font-family:verdana;">Hi, to anyone that is listening (anyone?)</span><br /><br /><span style="font-family:verdana;">echo echo echo</span><br /><div><span class="Apple-style-span" style="font-family:verdana;"><br /></span></div><div><span class="Apple-style-span" style="font-family:verdana;">I haven't been working on this project due to some other work that is taking all my time and is of a higher priority.<br /></span></div><span class="Apple-style-span" style="font-family:verdana;"><br /></span><div><span class="Apple-style-span" style="font-family:verdana;">But I have not forgotten about FZVS and it will be finished.</span></div>Unknownnoreply@blogger.com5tag:blogger.com,1999:blog-6911258264312298491.post-64110594584667489042008-08-31T23:09:00.001-07:002008-09-08T16:06:41.254-07:00Collisions<div style="text-align: justify;"><span style="font-family:verdana;">Sorry about the delay in updates.. I have been very busy. The purpose of this post is to discuss car collisions in F-Zero VS.</span><br /><br /><span style="font-family:verdana;">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.<br /></span><br /><span style="font-family:verdana;">The solution to this is to:</span><br /><br /><span style="font-family:verdana;">a) Make sure that each emulator instance only rebounds its own player during a player-opponent collision by patching occurrences of the code <span style="color: rgb(255, 0, 0);">99 20 0B STA $0B20,Y to NOPs at ROM addresses 00:BDB2, 00:BDD5, 00:BDEF and 00:BDFE</span>.</span><br /><br /><span style="font-family:verdana;">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 <span style="color: rgb(255, 0, 0);">9D 20 0B STA $0B20,X to NOPs at ROM addresses 00:BDAE, 00:BDCB and 00:BDE5</span>.</span></div>Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-6911258264312298491.post-7032400495216445922008-07-29T22:12:00.000-07:002008-07-30T22:08:47.753-07:00Video<object height="350" width="425"> <param name="movie" value="http://www.youtube.com/v/3LAVGMPbCiY"> <embed src="http://www.youtube.com/v/3LAVGMPbCiY" type="application/x-shockwave-flash" height="350" width="425"></embed> </object><br /><span style="font-size:100%;"><span style="font-family:verdana;">Source code is coming soon!</span></span>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6911258264312298491.post-60987041990679357342008-07-29T22:06:00.000-07:002008-08-31T23:35:03.406-07:00Tech stuff<div style="text-align: justify;"><span style="font-size:100%;"><span style="font-family:verdana;">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):</span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">1) To disable any menu selections at the title screen other than the first option, patch <span style="color: rgb(255, 0, 0);">03:8176 INC to NOP</span>:</span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[(0x8000*3)+0x0176] = 0xEA;</span></span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">2) To disable the 'demo race' at title screen (as this will trigger game states we don't need), patch <span style="color: rgb(255, 0, 0);">03:8143 BNE $8148 to BRA $8148</span>:</span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[(0x8000*3)+0x0143] = 0x80;</span></span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">3) Then we wait for the player to select a car. To catch car selection, check memory status at <span style="color: rgb(255, 0, 0);">$7E:0055</span>. When it equals 0x03 we know a car has been selected. You can determine which car was selected by reading <span style="color: rgb(255, 0, 0);">$7E:005A</span> 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.</span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">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 <span style="color: rgb(255, 0, 0);">$7E:0055 == 0x05</span>. 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 <span style="color: rgb(255, 0, 0);">03/851F: A5 55 F0 74 LDA $55</span> to become <span style="color: rgb(255, 0, 0);">5C 1F 85 03 JMP 03851F</span>.</span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[(0x8000*3)+0x051F] = 0x5C;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[(0x8000*3)+0x0520] = 0x1F;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[(0x8000*3)+0x0521] = 0x85;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[(0x8000*3)+0x0522] = 0x03;</span></span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">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.</span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">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.</span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">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.</span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">We need to change the viewpoint of the car to match the fs location. To do this, we patch <span style="color: rgb(255, 0, 0);">00:D2EF A5 52 LDA $52 to A9 0x LDA #$x</span> where x is a value from the </span></span><span style="font-size:100%;"><span style="font-family:verdana;">internal representation of the </span></span><span style="font-size:100%;"><span style="font-family:verdana;">car selection (being bf, wg, gf, fs):</span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[0xD2EF-0x8000] = 0xA9;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[0xD2F0-0x8000] = x;</span></span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">To set the player car palette to be based on the player id, patch <span style="color: rgb(255, 0, 0);">00:D72B LDA $52 to LDA #$pid</span> where pid is the player id:</span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[0xD72B-0x8000] = 0xA9;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[0xD72C-0x8000] = pid;</span></span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">Then we can set the opponent car types, based on the data we received earlier. To do this, we write to RAM:</span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.RAM[0x1133] = x;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.RAM[0x1135] = y;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.RAM[0x1137] = z;</span></span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">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:</span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.RAM[0x1133] = player who is in the gf position;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.RAM[0x1135] = player who is in the wg position;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.RAM[0x1137] = player who is in the bf position;</span></span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">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 <span style="color: rgb(255, 0, 0);">0x0C41,</span></span></span><span style="color: rgb(255, 0, 0);"><span style="font-size:100%;"><span style="font-family:verdana;"> 0x0C43, </span></span><span style="font-size:100%;"><span style="font-family:verdana;">0x0C45,</span></span></span><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(255, 0, 0);"> 0x0C47</span> 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:</span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.RAM[0x0C41] = 0x0E;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.RAM[0x0C43] = 0x08;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.RAM[0x0C45] = 0x0A;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.RAM[0x0C47] = 0x0C;</span></span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">Finally we then make a few small patches that are needed to make things run smoothly. We patch the code at <span style="color: rgb(255, 0, 0);">00:D486 LDX #$00 to JMP $D4A7</span>, to skip the car loop iteration:</span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[0xD486-0x8000] = 0x4C;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[0xD487-0x8000] = 0xA7;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[0xD488-0x8000] = 0xD4;</span></span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">we patch the code at <span style="color: rgb(255, 0, 0);">00:D32B STA $1131,X to NOPs</span>, to make sure the car types are never overwritten:</span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[0xD32B-0x8000] = 0xEA;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[0xD32C-0x8000] = 0xEA;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[0xD32D-0x8000] = 0xEA;</span></span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">and to stop the player car palette from defaulting back to the original when it crosses the finish line, patch <span style="color: rgb(255, 0, 0);">00:8DB6 JSR $C782 to NOPs</span>:</span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[0x8DB6 - 0x8000] = 0xEA;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[0x8DB7 - 0x8000] = 0xEA;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[0x8DB8 - 0x8000] = 0xEA;</span></span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">8) Now I need to explain how the F-Zero game actually works.</span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">F-Zero tracks the progress of five displayed cars. The locations of these cars are stored at: <span style="color: rgb(255, 0, 0);">7E:0B70-0B79</span> (x values) and <span style="color: rgb(255, 0, 0);">7E:0B90-0B99</span> (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 :)</span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">What this means, is we need to make a few more modifications.</span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">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.</span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">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.</span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">The good news is we can solve both problems simply. We patch <span style="color: rgb(255, 0, 0);">00:DDFC JSR $DED0 to EA NOP * 3</span>:</span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[0xDDFC - 0x8000] = 0xEA;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[0xDDFD - 0x8000] = 0xEA;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[0xDDFE - 0x8000] = 0xEA;</span></span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">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 <span style="color: rgb(255, 0, 0);">00:DDDA JSR $DE57 to EA NOP * 3</span>:</span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[0xDDDA - 0x8000] = 0xEA;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[0xDDDB - 0x8000] = 0xEA;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[0xDDDC - 0x8000] = 0xEA;</span></span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">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 <span style="color: rgb(255, 0, 0);">00:8D3E LDA #$02 to LDA #$00</span>:</span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[0x8D3F - 0x8000] = 0x00;</span></span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">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 <span style="color: rgb(255, 0, 0);">00:C8FF F0 06 BEQ $C907 to be 80 06 BRA $C907</span>:</span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[0xC8FF - 0x8000] = 0x80;</span></span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">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 <span style="color: rgb(255, 0, 0);">00:CD84 90 03 BCC $CD89 to be 80 03 BRA $CD89</span>:</span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[0xCD84 - 0x8000] = 0x80;</span></span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">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:</span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[(0x8000*3)+0x051F] = 0xA5;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[(0x8000*3)+0x0520] = 0x55;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[(0x8000*3)+0x0521] = 0xF0;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[(0x8000*3)+0x0522] = 0x74;</span></span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">14) We skip the league and difficulty selection because it is already chosen for us by the server. I do this crudely by patching <span style="color: rgb(255, 0, 0);">03/8795: B0 35 BCS $87CC to BRA $87CC 80 35</span>:</span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[(0x8000*3)+0x0795] = 0x80;</span></span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">and by patching <span style="color: rgb(255, 0, 0);">03/87E6: 6B RTL</span> to be another <span style="color: rgb(255, 0, 0);">INC $55</span> (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:</span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[(0x8000*3)+0x07E6] = 0xE6;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[(0x8000*3)+0x07E7] = 0x55;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.ROM[(0x8000*3)+0x07E8] = 0x6B;</span></span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">15) We instead set the league and the track number by patching the RAM at <span style="color: rgb(255, 0, 0);">7E:0053</span> (track number) and <span style="color: rgb(255, 0, 0);">7E:005A</span> (league number).</span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.RAM[0x53] = track_num;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.RAM[0x5A] = league_num;</span></span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">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 <span style="color: rgb(255, 0, 0);">7E:0054 == 2, 7E:0055 == 0 and 7E:0056 == 2</span>:</span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">if((Memory.RAM[0x54] == 0x02) && (Memory.RAM[0x55] == 0x00) && (Memory.RAM[0x56] == 0x02))</span></span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">then we read the 16 bit value at <span style="color: rgb(255, 0, 0);">7E:0B70</span> (this means also 7E:0B71) to get the x value, and similarly <span style="color: rgb(255, 0, 0);">7E:0B90/1</span> for the y value. The car's orientation is at <span style="color: rgb(255, 0, 0);">7E:0BD1</span>.</span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">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 <span style="color: rgb(255, 0, 0);">7E:0B72/3,</span></span></span><span style="color: rgb(255, 0, 0);"><span style="font-size:100%;"><span style="font-family:verdana;">7E:0B74/5</span></span><span style="font-size:100%;"><span style="font-family:verdana;">, </span></span><span style="font-size:100%;"><span style="font-family:verdana;">7E:0B7</span></span><span style="font-size:100%;"><span style="font-family:verdana;">6/7 and </span></span><span style="font-size:100%;"><span style="font-family:verdana;">7E:0B92/3,</span></span><span style="font-size:100%;"><span style="font-family:verdana;">7E:0B94/5</span></span><span style="font-size:100%;"><span style="font-family:verdana;">, </span></span><span style="font-size:100%;"><span style="font-family:verdana;">7E:0B9</span></span><span style="font-size:100%;"><span style="font-family:verdana;">6/7</span></span></span><span style="font-size:100%;"><span style="font-family:verdana;">. Similarly the opponent orientation data is at <span style="color: rgb(255, 0, 0);">7E:0BD3, 7E:0BD5 and 7E:0BD7</span> where the order is based on the player id.</span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">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 <span style="color: rgb(255, 0, 0);">7E:0054</span> until it equals 3:</span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">if(Memory.RAM[0x54] == 0x03)</span><span style="color: rgb(102, 102, 102);"> game_state = GAMESTATE_RACEFINISHED;</span></span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">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.</span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.RAM[0x0B78] = 0;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.RAM[0x0B79] = 0;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.RAM[0x0B98] = 0;</span></span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;"><span style="color: rgb(102, 102, 102);">Memory.RAM[0x0B99] = 0;</span></span></span><br /></div>Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-6911258264312298491.post-28346279890989923452008-07-29T15:52:00.000-07:002008-08-31T23:35:29.073-07:00Some more info<div style="text-align: justify;"><span style="font-size:100%;"><span style="font-family:verdana;">1) Multiple players can select the same car type.</span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">2) The first car is always pink, the second is always blue, the third is always green and the fourth is always yellow regardless on the</span></span><span style="font-size:100%;"><span style="font-family:verdana;"> car type. I did it this way so that no one got confused who was who when the same car type was selected. Also it looks good! </span></span><span style="font-size:100%;"><span style="font-family:verdana;">The images below show </span></span><span style="font-size:100%;"><span style="font-family:verdana;">a three player game with a pink wild goose and two fire stingrays</span></span><span style="font-size:100%;"><span style="font-family:verdana;">.</span></span><br /><span style="font-size:100%;"><span style="font-family:verdana;">IMAGES: 1) player 1 and 2 starting views, and 2) car positioning and orientation working.</span></span><br /></div><span style="font-size:100%;"><span style="font-family:verdana;"><br /></span></span><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijaDN7OQFqaNmfblLy7VY8rKvba7IyE0lZvRpN75uJTsMC0rftSSBIP4RK-ep1n_Gquiv-mJof1KgN0VdQ6Ex2ThyphenhyphenBvM6yT0kZgh8dc_ZYaonvHUDQL59KUYYOjNwujV7FFbFVugzooFs/s1600-h/1.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijaDN7OQFqaNmfblLy7VY8rKvba7IyE0lZvRpN75uJTsMC0rftSSBIP4RK-ep1n_Gquiv-mJof1KgN0VdQ6Ex2ThyphenhyphenBvM6yT0kZgh8dc_ZYaonvHUDQL59KUYYOjNwujV7FFbFVugzooFs/s320/1.jpg" alt="" id="BLOGGER_PHOTO_ID_5228579810821212322" border="0" /></a><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiB_sPHTfhW8NBpoTEuG2x32lN2KJTa7hAOAE6zfTIZtqIhI3Q0q38NOv8R62F3lZh99ljh_NslDKRfD1fXi9d0Go0L0t0oSRBP4Z6q_vuatNiO5t1s2SuoN7gCZYFGPdq4YEVdXKglPK4/s1600-h/2.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiB_sPHTfhW8NBpoTEuG2x32lN2KJTa7hAOAE6zfTIZtqIhI3Q0q38NOv8R62F3lZh99ljh_NslDKRfD1fXi9d0Go0L0t0oSRBP4Z6q_vuatNiO5t1s2SuoN7gCZYFGPdq4YEVdXKglPK4/s320/2.jpg" alt="" id="BLOGGER_PHOTO_ID_5228580404926703730" border="0" /></a><br /><div style="text-align: justify;"><span style="font-size:100%;"><span style="font-family:verdana;">3) This is not just a SNES ROM and will not work on any normal emulator. It is a 'system' that requires a specific version of Snes 9x that I modified in order to work as well as server software.</span></span><br /><br /><span style="font-size:100%;"><span style="font-family:verdana;">4) F-Zero uses a series of lap checkpoints for updating the race progression (things like opponent steering, when an opponent should overtake you, ranks etc). As you can see above, I have the rank shown incorrectly (green car is first when it should be third) but when the car moves to the next checkpoint (very close) the rank will be updated correctly.</span></span><br /></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6911258264312298491.post-19035680152033255022008-07-29T15:22:00.000-07:002008-08-31T23:35:49.806-07:00What is FZVS?<span style="font-family: verdana;font-family:verdana;font-size:100%;" >This is a project that most people will not get the point of. Honestly, I don't know anyone in my real life that would see this as anything but a waste of time. But maybe there are those out there on the internet that DO get what its about, and this is for them.</span> <p style="font-family: verdana;font-family:verdana;" class="style1" align="justify"><span style="font-size:100%;">F-Zero VS is the result of some work I did due to nostalgia. The original F-Zero SNES game was amazing for its time. The graphics used full screen Mode 7 (unlike Super Mario Kart which sacrifices full screen Mode 7 in singleplayer in order to use the same half screen code for multiplayer). And the music... some of the best ever - I CANNOT STRESS how much I love the music!! When I was a kid, the entire futuristic atmosphere amazed me.</span></p> <p style="font-family: verdana;font-family:verdana;" class="style1" align="justify"><span style="font-size:100%;">I really wanted to do some work with this game, and my first idea was to build a track editor, but then I found some people that have already commenced work on that. </span></p> <p style="font-family: verdana;font-family:verdana;" class="style1" align="justify"><span style="font-size:100%;">So instead I thought.. why not add two player functionality to F-Zero? After all, that was the one thing missing from the original game. I thought about split screening it but quickly realised it just wasn't feasible. And it wouldn't look good as the field of vision would need to be cropped. So my solution was to allow two player gameplay on two seperate screens. The best way to achieve this was by making it networkable. And then I thought, if it's going to be networkable, why limit it to two players?</span></p> <p style="font-family: verdana;font-family:verdana;" class="style1" align="justify"><span style="font-size:100%;">And that is <strong>F-Zero VS</strong>. Four player, networked F-Zero. It's a mixture of ROM hack, Snes9x modification and server code. It works as follows:</span></p> <p style="font-family: verdana;font-family:verdana;" class="style8" align="justify"><span style="font-size:100%;">1. The server is started on a networked computer.<br /></span></p> <p style="font-family: verdana;font-family:verdana;" class="style7" align="justify"><span style="font-size:100%;">2. Client computers each start the modified Snes9x emulator and specify the IP address and port of the server. The F-Zero ROM is then loaded by the emulator. It shouldn't matter whether it is headerless or an overdump or whatever as long as the ROM itself is the US version.<br /></span></p><p style="font-family: verdana;font-family:verdana;" class="style7" align="justify"><span style="font-size:100%;">(eg. </span><span style="font-weight: bold; font-style: italic;font-size:100%;" >F-ZERO (U) [!]</span><span style="font-size:100%;"> if you know what that means.)<br /></span></p> <p style="font-family: verdana;font-family:verdana;" class="style7" align="justify"><span style="font-size:100%;">3. The emulator then proceeds to run the game. 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.</span></p> <p style="font-family: verdana;font-family:verdana;" class="style8" align="justify"><span style="font-size:100%;">4. Each emulator sends the state of their controlled car (location, orientation etc) to the server. Then it requests the state of all the other cars.</span></p> <p style="font-family: verdana;font-family:verdana;" class="style7" align="justify"><span style="font-size:100%;">5. The states of all the other cars obtained from the server are used to update the car states in the client game.</span></p> <p style="font-family: verdana;font-family:verdana;" class="style1" align="justify"><span style="font-size:100%;">This project actually wasn't that challenging, fairly standard ROM disassembly. But it was a lot of fun. Most of the work was done on an Asus EEE 900 during long plane and ferry trips while I was on holiday (just got back last night).<br /></span></p>Unknownnoreply@blogger.com5