Monday, January 23, 2017

Spyro, MGS and CTR save format

I documented this when I was making plugins for MemcardRex. If anyone needs this info for some reason, here it is.
Offsets are for .mcs single save format.

Spyro the Dragon:
Level name Gems, Dragons, Eggs
Artisans Home 100, 4, 0
Stone Hill 200, 4, 1
Dark Hollow 100, 3, 0
Town Square 200, 4, 1
Toasty 100, 1, 0
Sunny Flight 300, 0, 0
Peace Keepers Home 200, 3, 1
Dry Canyon 400, 4, 1
Cliff Town 400, 3, 1
Ice Cavern 400, 5, 0
Doctor Shemp 300, 1, 0
Night Flight 300, 0, 0
Magic Crafters Home 300, 3, 2
Alpine Ridge 500, 4, 1
High Caves 500, 3, 2
Wizard Peak 500, 3, 2
BlowHard 400, 1, 0
Crystal Flight 300, 0, 0
Beast Makers Home 300, 2, 0
Terrace Villiage 400 2, 0
Misty Bog 500 4 0
Tree Tops 500 3 0
MetalHead 500 1 0
Wild Flight 300 0 0
Dream Weavers Home 300 3 0
Dark Passage 500 5 0
Lofty Castle 400 3 0
Haunted Towers 500 3 0
Jaques 500 2 0
Icy Flight 300 0 0
Gnorc Gnexus 200 2 0
Gnorc Cove 400 2 0
Twilight Harbor 400 2 0
Gnasty Gnorc 500 0 0
Gnasty's Loot 2000 0 0

Save structure information:
Values are stored in the little endian byte order

0x000 - 128 bytes (Save header)
0x080 - 512 bytes (Save title + icon)
0x280 - 1536 bytes (Slot 1)
0x880 - 1536 bytes (Slot 2)
0xE80 - 1536 bytes (Slot 3)

Slot structure:
0x280 - 8 bit (Start location. Read as decimal: World x 10 + Stage)
0x281 - 8 bit (SFX volume) - Values range from 0 to 10
0x282 - 8 bit (Music volume) - Values range from 0 to 10
0x284 - 8 bit (Passive/Active flag) - Passive is 82 and Active is 2. Probably used for something else too
0x288 - 8 bit (Stereo/Mono flag) - Stereo is 0 and Mono is 1
0x28B - 8 bit (Lives) - Maximum is 255 but only 2 digits will be visible ingame
0x2C0 - 8 bit (Unlocked level flags) - Values range from 0 to 1
0x308 - 35 x 8 bit (Saved dragons)
0x32C - 35 x 16 bit (Gems)
0x374 - 16 x 8 bit (Eggs)
0x38C - 32 x 8 bit (Flags for collected items)
0x80C - 32 bit (Checksum) - Sum of all previous bytes from beginning of the slot

Additional information:
Each slot offsets by 0x600 from the previous one.

Game progress percentage (120 % max):
70% - Number of gems (14000 max)
40% - Number of saved dragons (80 max)
10% - Unknown


Crash Team Racing:
Character indexes:
0x0 - Crash Bandicoot
0x1 - Dr. Neo Cortex
0x2 - Tiny Tiger
0x3 - Coco Bandicoot
0x4 - N. Gin
0x5 - Dingodile
0x6 - Polar
0x7 - Pura
0x8 - Pinstripe
0x9 - Papu Papu
0xA - Ripper Roo
0xB - Komodo Joe
0xC - Dr. N. Tropy
0xD - Penta Penguin
0xE - Fake Crash
0xF - Nitrous Oxide (game locks up)

Unsupported indexes (0xF and up) lead to game crashing.
If the index is 0xFFFF save is not active.

Save structure information:
Values are stored in the little endian byte order.

0x0000 - 128 bytes (Save Header)
0x0080 - 256 bytes (Save title + icon)
0x0180 - 80 bytes (1st save slot)
0x01D0 - 80 bytes (2nd save slot)
0x0220 - 80 bytes (3rd save slot)
0x0270 - 80 bytes (4th save slot)

0x0184 - 8 bit (Colectables flags 1)
bit 1 - Unknown
bit 2 - Unknown
bit 3 - Unknown
bit 4 - Unknown
bit 5 - Unknown
bit 6 - Unknown
bit 7 - Dingo Canyon (trophy)
bit 8 - Dragon Mines (trophy)

0x0185 - 8 bit (Colectables flags 2)
bit 1 - Blizzard Bluff (trophy)
bit 2 - Crash Cove (trophy)
bit 3 - Tiger Temple (trophy)
bit 4 - Papu's Pyramid (trophy)
bit 5 - Roo's Tubes (trophy)
bit 6 - Hot Air Skyway (trophy)
bit 7 - Sewer Speedway (trophy)
bit 8 - Mystery Caves (trophy)

0x0186 - 8 bit (Colectables flags 3)
bit 1 - Cortex Castle (trophy)
bit 2 - N. Gin Labs (trophy)
bit 3 - Polar Pass (trophy)
bit 4 - Oxide Station (trophy)
bit 5 - Coco Park (trophy)
bit 6 - Tiny Arena (trophy)
bit 7 - Dingo Canyon (blue relic)
bit 8 - Dragon Mines (blue relic)

0x0187 - 8 bit (Colectables flags 4)
bit 1 - Blizzard Bluff (blue relic)
bit 2 - Crash Cove (blue relic)
bit 3 - Tiger Temple (blue relic)
bit 4 - Papu's Pyramid (blue relic)
bit 5 - Roo's Tubes (blue relic)
bit 6 - Hot Air Skyway (blue relic)
bit 7 - Sewer Speedway (blue relic)
bit 8 - Mystery Caves (blue relic)

0x0188 - 8 bit (Colectables flags 5)
bit 1 - Cortex Castle (blue relic)
bit 2 - N. Gin Labs (blue relic)
bit 3 - Polar Pass (blue relic)
bit 4 - Oxide Station (blue relic)
bit 5 - Coco Park (blue relic)
bit 6 - Tiny Arena (blue relic)
bit 7 - Slide Coliseum (blue relic)
bit 8 - Turbo Track (blue relic)

0x0189 - 8 bit (Colectables flags 6)
bit 1 - Dingo Canyon (gold relic)
bit 2 - Dragon Mines (gold relic)
bit 3 - Blizzard Bluff (gold relic)
bit 4 - Crash Cove (gold relic)
bit 5 - Tiger Temple (gold relic)
bit 6 - Papu's Pyramid (gold relic)
bit 7 - Roo's Tubes (gold relic)
bit 8 - Hot Air Skyway (gold relic)

0x018A - 8 bit (Colectables flags 7)
bit 1 - Sewer Speedway (gold relic)
bit 2 - Mystery Caves (gold relic)
bit 3 - Cortex Castle (gold relic)
bit 4 - N. Gin Labs (gold relic)
bit 5 - Polar Pass (gold relic)
bit 6 - Oxide Station (gold relic)
bit 7 - Coco Park (gold relic)
bit 8 - Tiny Arena (gold relic)

0x018B - 8 bit (Colectables flags 8)
bit 1 - Slide Coliseum (gold relic)
bit 2 - Turbo Track (gold relic)
bit 3 - Dingo Canyon (platinum relic)
bit 4 - Dragon Mines (platinum relic)
bit 5 - Blizzard Bluff (platinum relic)
bit 6 - Crash Cove (platinum relic)
bit 7 - Tiger Temple (platinum relic)
bit 8 - Papu's Pyramid (platinum relic)

0x018C - 8 bit (Colectables flags 9)
bit 1 - Roo's Tubes (platinum relic)
bit 2 - Hot Air Skyway (platinum relic)
bit 3 - Sewer Speedway (platinum relic)
bit 4 - Mystery Caves (platinum relic)
bit 5 - Cortex Castle (platinum relic)
bit 6 - N. Gin Labs (platinum relic)
bit 7 - Polar Pass (platinum relic)
bit 8 - Oxide Station (platinum relic)

0x018D - 8 bit (Colectables flags 10)
bit 1 - Coco Park (platinum relic)
bit 2 - Tiny Arena (platinum relic)
bit 3 - Slide Coliseum (platinum relic)
bit 4 - Turbo Track (platinum relic)
bit 5 - Dingo Canyon (CTR token)
bit 6 - Dragon Mines (CTR token)
bit 7 - Blizzard Bluff (CTR token)
bit 8 - Crash Cove (CTR token)

0x018E - 8 bit (Colectables flags 11)
bit 1 - Tiger Temple (CTR token)
bit 2 - Papu's Pyramid (CTR token)
bit 3 - Roo's Tubes (CTR token)
bit 4 - Hot Air Skyway (CTR token)
bit 5 - Sewer Speedway (CTR token)
bit 6 - Mystery Caves (CTR token)
bit 7 - Cortex Castle (CTR token)
bit 8 - N. Gin Labs (CTR token)

0x018F - 8 bit (Colectables flags 12)
bit 1 - Polar Pass (CTR token)
bit 2 - Oxide Station (CTR token)
bit 3 - Coco Park (CTR token)
bit 4 - Tiny Arena (CTR token)
bit 5 - Unknown
bit 6 - Unknown
bit 7 - Ripper Roo (boss)
bit 8 - Papu Papu (boss)

0x019C - 9 bytes (User name, standard ASCII, 8 letters + null char)
0x01AE - 16 bit (Game character)

0x02C8 - 8 bit (Character unlockables 1)
bit 1 - Unknown
bit 2 - Unknown
bit 3 - Parking Lot (Battle arena)
bit 4 - The North Bowl (Battle arena)
bit 5 - Lab Basement (Battle arena)
bit 6 - Dr. N. Tropy
bit 7 - Penta Penguin
bit 8 - Ripper Roo

0x02C9 - 8 bit (Character unlockables 2)
bit 1 - Papu Papu
bit 2 - Komodo Joe
bit 3 - Pinstripe
bit 4 - Fake Crash
bit 5 - Unknown
bit 6 - Unknown
bit 7 - Unknown
bit 8 - Unknown

0x02CC - 8 bit (General unlockables)
bit 1 - Unknown
bit 2 - Unknown
bit 3 - Unknown
bit 4 - Unknown
bit 5 - Scrapbook mode
bit 6 - Unknown
bit 7 - Unknown
bit 8 - Unknown

0x17FE - 16 bit (Checksum, big endian)

Checksum calculation:

private uint GetChecksumCTR(byte[] InputData)
{
//Simulated PS1 registers
uint r2 = 0;
uint r3 = 0;
uint r4 = 0;
uint r5 = 0;
uint r6 = 0;
uint r7 = 0;

//Checksum calculation
for (uint i = 0; i < 5760; i++)
{
r5 = InputData[i + 0x180];
r3 = 0x7;
r7 = 0x10000;
r6 = r7;
r6 = r6 | 0x1021;

//Erase old checksum
InputData[0x17FE] = 0x00;
InputData[0x17FF] = 0x00;

while (r3 < 0xFFFF)
{
r4 = r4 << 0x1;
r2 = r5 >> (int)r3;
r2 = r2 & 0x1;
r4 = r4 | r2;
r2 = r4 & r7;

if (r2 != 0) r4 = r4 ^ r6;

r3 = (r3 + 0xFFFF) & 0xFFFF;
}
}
return r4;
}


Metal Gear Solid:
Weapon order:
Socom
FA-MAS
Grenades
Nikita
Stinger
Claymore
C4
Stun grenades
Chaff grenades
PSG-1

Item order:
Cigarettes
Magnifying scope
Cardboard box A
Cardboard box B
Cardboard box C
Night-vision goggles
Thermal goggles
Gas mask
Body armor
Ketchup
Stealth
Bandana
Camera
Ration
Cold medicine
Diazepam
PAL card key
ID card
Timer bomb
Mine detector
MO disc
Rope
Handkerchief
Suppressor

Location order:
Dock
Heliport
Tank Hangar
Cell
Medi room
Armory
Armory Sth
Canyon
Nuke Bldg 1
Nuke Bldg. B1
Cmnder room
Nuke Bldg. B2
Lab
Cave
U.Grnd Pssge
Comm Twr A
Roof/Comm Twr
Comm Twr B
Twr Wall A
Walkway
Snowfield
Blast Furnance
Cargo Elev.
Warehouse
Warehouse Nth
U.Grnd Base 1
U.Grnd Base 2
U.Grnd Base 3
Cmnd room
Spply Rte.
Esc Route

Save identifier:
GHHMMCLI

G - Magic letter (G - game, V - training data, C - photo)
HH - Hours
MM - Minutes (EZ starts with 0, NM with q)
C - New or cleared game (Starts with @ - New game, H - Disc 2)
L - Location (Starts with A - Dock)
I - Identifier between similar saves (Starts with A)

This is just for info when loading game. Identifier data is not used in game.

Save structure information:
Values are stored in the little endian byte order.

0x0000 - 128 bytes (Save Header)
0x0080 - 512 bytes (Save title + icon)
0x0280 - 2560 bytes (Save data)
0x0C80 - 2560 bytes (Save data mirror, not used when loading)
0x1680 - 2560 bytes (Save data mirror, not used when loading)

0x0184 - 32 bit (Checksum) - CRC32
0x0190 - 32 bit (Game time) - Counted in frames (NTSC - 60 fps, PAL - 50 fps)
0x01BC - 32 bit (Generic flags, unknown at this time)
0x01C2 - 16 bit (Game difficulty) - 0-Easy, 1-Normal, 2-Hard, 3-Extreme
0x01C4 - 16 bit (Option flags) - ????R??? ???????? - (When R is active radar is invisible)
0x01D6 - 16 bit (Current health) - Anything above 1400 causes issues
0x01D8 - 16 bit (Maximum health) - Anything above 1400 causes issues
0x01E2 - 10 x 16 bit (Current weapon units) - If the value is positive weapon is in stock
0x01F6 - 10 x 16 bit (Maximum weapon units)
0x020A - 23 x 16 bit (Current item units) - If the value is greater then 0 item is in stock
0x023A - 16 bit (Maximum Rations)
0x023C - 16 bit (Maximum Cold medicines)
0x023E - 16 bit (Maximum Diazepams)
0x0270 - 8 bit (Number of saves)
0x02DA - 8 bit (Torture flags) ????O??? - (When O is activated Meryl dies)

Saturday, January 14, 2017

BCLoader fix

In 2012 I made a loader plugin for Black Chocobo save editor so users can edit FF7 saves
directly from MemcardRex.

It simply takes a single FF7 save, stores it to temp directory, sends it to Black Chocobo and waits for the application to close so it can put the save back to MemcardRex.

I named the temp file "FF7SaveData" and that worked when I tested the plugin.
However in the mean time Black Chocobo was updated and now it expects a decently named file to
detect it as a single save (eg. "BASCUS-94163FF7-S01").

Because of that BCLoader 0.1 is not usable with Black Chocobo any more and
the save is not detected as Final Fantasy VII save.


This has escaped me as I don't use Black Chocobo.
Fortunately user Jack Barnard pointed out the problem with the plugin.

So I fixed the problem and got the plugin working once again.


So, here it is. Grab the updated plugin and replace old "BCLoader.dll" in
plugins directory with the new one. 

Download link:

Thursday, October 20, 2016

MemcardRex mobile

Status update just so you know that I'm alive folks.

I've started working on the mobile version of MemcardRex.
It's not a port of the desktop version though, once again I'm starting from scratch.

It's a Cordova application written using Meteor framework.

 

Features I'm aiming for:
Support for all file types desktop version supports.
Single save import / export feature.
Multiple Memory Cards opened at the same time.
Custom container format so you can have a single Memory Card with more than 15 saves.

It will behave a little differently than a desktop version.
A single save will be shown only once but with the indication of how much slots (space) it uses.
If a limit of 15 slots is surpassed then only a custom container format will be available for saving.

I plan to have a free version with limited features (but still very usable)
and a paid one with full features. No ads in any of those, I hate ads.

If you have any suggestions please post a comment.

Don't ask for release date though, I'm not even remotely sure when will that be.

Sunday, October 5, 2014

Memory Card conversions

2015-06-02:
I don't have a PSP anymore so I'm not able to make save conversions.
I will update this post if anything changes.

I have been getting bunch of requests lately for Memory Card conversions
from .mcr to PSP and PS Vita format (VMP).



There have been requests on ngemu, blog comments and emails and probably
on some other communities where I frequent.

To keep thing neatly organized I'll attach those saves to this post and maybe
we can even help someone else by using those converted saves.

So, consider this the official "ask Shendo to convert my save" post.

Just comment on this post with a link to your save and I'll convert
and attach saves when I get the chance.

Saves:
Final Fantasy VIII (US) by Eric Vincent
Xenogears (US) by Eric Vincent
Final Fantasy IX (US) by Eric Vincent
Bushido Blade 2 (US) by Cjay2014
Final Fantasy VII/VIII (US) by Trapped
Xenogears (US) by David Tonka
Breath of Fire III (US) by Lt.Dan
Final Fantasy IX (US) by Romans5.8
Final Fantasy VII (EU) by Ex-SOLDIER
Final Fantasy VIII (EU) by Ex-SOLDIER
Final Fantasy IX (EU) by Zappyros
Final Fantasy IX (EU) by Kosaka
Legend of Mana (US) by Agsboy
Final Fantasy IX (US) by Knkma000
Final Fantasy VII/VIII (US) by Craig A O'Donnell-Vicente
Crash Team Racing / Final Fantasy IX (EU) by Ex-SOLDIER
Final Fantasy VIII (US) by Ddx92
Xenogears (US) by Michael1986
Tobal 2 / Saga Frontier / Front Mission 2 / Final Fantasy VII / Tactics / Einhander / Bushido Blade / Brave Fencer Mushashi by Fushigina
Chrono Cross (US) by J. Hampe
Final Fantasy IX / Digimon (EU) by VoiD3d
Final Fantasy VII/VIII/IX (EU) / Resident Evil 1 / 2 (US) by Noctis_XV
Breath of Fire 4 (US) by Dustin Weith
Legend of Dragoon (US) by B-train
Arc the Lad 2 (US) by Ygna
Parasite Eve 1/2 (US) by Justin Chambers
Final Fantasy VIII (EU) by RehiiX
Wild Arms 2, FF9, Legend of Legaia (US) by Eric Taylor
Final Fantasy VII (US) by Thurac
Final Fantasy VIII (EU, US) by Havenbrook

Sunday, August 10, 2014

MemcardRex goes open source

I decided to release the source code for MemcardRex in a hope that community
will contribute to it and keep the project alive.

Due to some other ongoing projects of mine I'm unable to work on MemcardRex
as much as I want to and it would be a shame to let the project die.


I have set up a git repository page which can be reached by following this link:
MemcardRex Git repository

--
Also, if anyone is up for it a Gtk# port of the application would be much appreciated
as non Windows platform are lacking a serious PS1 Memory Card editor.

Thursday, July 10, 2014

Gtk# version of BIOSGet released.

Lately I have been using Linux and I noticed that my BIOSGet application
was not working properly with Mono.

That's why I decided to port the application to Gtk#.

So here it is. It should work properly on Linux and OS X if you have latest Mono runtime installed.





Download:
BIOSGet 0.1 Gtk#

Saturday, March 15, 2014

PadTest (PS1 homebrew)




Every so often I get or buy a cheap broken PlayStation controller and I fix it.

With that I found myself in need for a controller test application
since that feature is pretty crude in standard games.

So I decided to write my own and upon completing it I'm sharing it with community.

Usage:
Burn a bin/cue image to CD and boot it on your console.
After that connect a controller of your choice to either port and test it's buttons.

Analog controllers should automatically switch to analog "red led mode".
To test rumble press L3 for big motor and R3 for small motor.

This software is intended to be ran on the actual PlayStation 1 or PSone console.
Since it's using direct memory access to SIO ports it may not work on emulators or other
consoles (PlayStation 2).

Download:
PadTest 1.0