------------------------------------------------------------------------------- | Secret of Evermore SRAM Document 1.1 | by John David Ratliff | | The most recent version of this guide can always be found at | http://games.technoplaza.net/soesrame/sram-doc.txt | | Copyright (C) 2006,2008 emuWorks (http://games.technoplaza.net/) | Permission is granted to copy, distribute and/or modify this document | under the terms of the GNU Free Documentation License, Version 1.2 | or any later version published by the Free Software Foundation; | with no Invariant Sections, no Front-Cover Texts, and no Back-Cover | Texts. A copy of the license can be found at | http://www.gnu.org/licenses/fdl.html ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- | Table of Contents ------------------------------------------------------------------------------- - 1.0 Introduction - 2.0 Copyright Notice - 3.0 Revision History - 4.0 The SRAM - 4.1 SRAM Basics - 4.2 SRAM Offsets - 4.3 The Sanity Algorithm - 5.0 soesrame - Secret of Evermore SRAM Editor - 6.0 Credits & Acknowledgements - 7.0 Contact Information ------------------------------------------------------------------------------- | 1.0 Introduction ------------------------------------------------------------------------------- This document is a guide to the Secret of Evermore SRAM, the section of memory in the Secret of Evermore cartridge used to save your progress. SNES emulators create a special file to store this memory. These are known as SRAM files and generally have a .srm extention (ZSNES and Snes9x both use this extension). This guide will describe the SRAM, what it stores and where, and how to edit it to change your save games. For a program that edits the SRAM, see section 5.0. I consider SRAM editing superior to save state editing for two reasons. First, generally only one emulator can read any particular save state file, so save state hacking only works if you use that particular emulator. Second, save state formats can change between emulator revisions, which renders state editing documents useless. There are several old DOS save state editors and documents for Nesticle save states. As nearly no one still uses nesticle, all those programs and documents are useless. There are almost as many documents and programs for ZSNES save states, but the ZSNES save state format has changed so often, most of these programs and documents are also useless. Save state editors/documents are more popular than SRAM editors/documents because they are easier to change. Because the SRAM employs a battery to keep the data, and the battery eventually dies, SRAM files need to be sanity checked to see if the battery is still functioning. This leads to extra information stored in the SRAM that is used to test the validity of the data. When you edit SRAM files, you must also correct this sanity data, or the game will think the SRAM is not valid, and you won't be able to play your edited games. ------------------------------------------------------------------------------- | 2.0 Copyright Notice ------------------------------------------------------------------------------- This document is Copyright (C) 2006,2008 emuWorks (http://games.technoplaza.net/) Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license can be found at http://www.gnu.org/licenses/fdl.html Basically, it is free documentation in much the same way software under the GNU General Public License is free software. You can modify it, redistribute it, sell it, publish it, etc. ------------------------------------------------------------------------------- | 3.0 Revision History ------------------------------------------------------------------------------- Version 1.1 - Friday, January 25, 2008 - Minor typos fixed - Updated name alphabet information for non-English versions. - Added missing Dog's Experience offset. - Updated checksum information for European versions. - Updated sanity program for European versions. Version 1.0 - Sunday, September 10, 2006 - First Public Release ------------------------------------------------------------------------------- | 4.0 The SRAM ------------------------------------------------------------------------------- This section details the SRAM format used by Secret of Evermore. ------------------------------------------------------------------------------- | 4.1 SRAM Basics ------------------------------------------------------------------------------- Secret of Evermore, like most SNES games, used an SRAM of 0x2000 (8 KB) bytes to store its information. Up to four games could be save. Each game used 0x331 bytes of SRAM. This means 0xCC4 bytes of SRAM are reserved for the game data, with 0x133C bytes used for other things (some unused). In this document, we are only interested in the 0xCC4 bytes of save game data. Not all of the information contained in the save game data is known. Most of what is undocumented is related to quest progress and opened or already found treasure. The only major items of interest that I've yet to find are the save location, and the rare quest items. Here is a short listing of what is known in no particular order. The sanity (aka checksum) data, the known alchemies and their levels, the boy and dog's stats (name, experience, level, hp, and mp), the money (talons, jewels, gold coins, and credits), and the inventory (alchemy ingredients, items, armors, weapons, helmets, gauntlets, collars, trade goods, and charms). The first game starts at 0x2 in the SRAM, and after its 0x331 bytes, the second game starts and so on for the four games. The next section will present the SRAM offsets and their meanings. ------------------------------------------------------------------------------- | 4.2 SRAM Offsets ------------------------------------------------------------------------------- This information is presented in no particular order. Similar information will be grouped together. When an offset is listed, this offset is relative to the start of the game data. For example, if I said the boy's name is at offset 0x26, this would be 0x28 (0x2 + 0x26) from the start of SRAM for game 1, and 0x359 (0x2 + 0x331 + 0x26), and so on. Data in the SRAM is stored in little endian format, the format used by the SNES processor. This means words are stored with their least significant byte first. For instance, 400 is 0x190 in hex, which is two bytes 0x01 and 0x90. In little endian, this would be 0x9001 [90 01]. Mainly, this just means reverse the bytes. There are plenty of endian guides on the web if you need a more in-depth explanation. ---------------------------------------------------- Sanity Data - the sanity/checksum word 0x0 (2 bytes) ---------------------------------------------------- ---------------------------------------------------- Boy's Stats 0x26 (name) 0x9D (level) 0x6E (current HP, 2 bytes) 0x8E (max HP, 2 bytes) 0x9A (experience, 3 bytes) Dog's Stats 0x4A (name) 0xDE (level) 0xAF (current HP, 2 bytes) 0xCF (max HP, 2 bytes) 0xDB (experience, 3 bytes) ---------------------------------------------------- The boy and dog's names have storage space for 34 characters (null terminated). However the game limits you to 15 character names. Using longer names is untested. The name is ASCII encoded, and names can consist of the entire alphabet (upper and lowercase), the numbers 0-9, and the characters , (comma), . (period), ! (exclamation point), ' (apostrophe), \ (backslash), - (hyphen), & (ampersand), # (pound), and (space). This is the alphabet the game limits you to using. Using characters outside this alphabet is untested. The German and Spanish versions have slightly different alphabets for the names. In the Spanish version, # is replaced by the ñ. It is encoded in the name with the value 0xD7, not the unicode value 0x00F1. In the German version, the numbers 0, and 4-9 are replaced by the capital and lower case vowels with umlauts and the eszett ß character. Their values are encoded as follows: ----------------- A umlaut = 0xCB O umlaut = 0xDB U umlaut = 0xDF a umlaut = 0xE3 o umlaut = 0xEF u umlaut = 0xF3 eszett = 0xC6 ----------------- The byte immediately after the character's name must be the null terminator (00). If there is no terminator, the game will crash on load. The valid range for levels are 1-99. The valid range for hp is 0-999. Setting levels above what your experience calls for is untested, as it setting a current HP above your max HP. The character's max HP is tied to their level. If you change it, the game will change it back as soon as you get hit or leave your current area. It is therefore pointless to edit this value. The valid range for experience is 0-7562471. The high value is the dog's level 99 experience. Anything more than that is pointless. The next offsets are for the money types in the game. Their valid range is 0-16,777,215. The high value is the max value for an unsigned 24-bit number. ---------------------------------------------------- 0xFC (Talons, 3 bytes) 0xFF (Jewels, 3 bytes) 0x102 (Gold Coins, 3 bytes) 0x105 (Credits, 3 bytes) ---------------------------------------------------- The next offsets are for the weapon inventory. There is a single bit for each weapon. The first value is the offset in the SRAM, and the second is the bit that controls it. A set bit (1) means you have the weapon, and a clear bit (0) means you do not have it. Bit numbers start at 0 and go through 7 and run right to left. For example, in the byte with bit pattern 10010010, bit 0 is clear and bit 7 is set. ---------------------------------------------------- 0x279 bit 1 (Bone Crusher) 0x279 bit 2 (Gladiator Sword) 0x279 bit 3 (Crusader Sword) 0x279 bit 4 (Neutron Blade) 0x279 bit 5 (Spider's Claw) 0x279 bit 6 (Bronze Axe) 0x279 bit 7 (Knight Basher) 0x27A bit 0 (Atom Smasher) 0x27A bit 1 (Horn Spear) 0x27A bit 2 (Bronze Spear) 0x27A bit 3 (Lance) 0x27A bit 4 (Laser Lance) 0x27A bit 5 (Bazooka) ---------------------------------------------------- The next set of offsets are for the weapon levels. The first offset is for the major level (1-3), and the second is for the minor (power up progression). The minor level ranges from 0-255. The status screen only shows values from 0-99. To convert between the actual value and the shown value, just divide the minor level by 2.56 and drop the decimal places. ---------------------------------------------------- 0x116 0x115 (Bone Crusher) 0x118 0x117 (Gladiator Sword) 0x11A 0x119 (Crusader Sword) 0x11C 0x11B (Neutron Sword) 0x11E 0x11D (Spider's Claw) 0x120 0x11F (Bronze Axe) 0x122 0x121 (Knight Basher) 0x124 0x123 (Atom Smasher) 0x126 0x125 (Horn Spear) 0x128 0x127 (Bronze Spear) 0x12A 0x129 (Lance) 0x12B 0x12A (Laser Lance) 0x13E 0x13D (Dog's Attack Level) ---------------------------------------------------- The next set of offsets are for the alchemy ingredients. Their valid range is from 0-99. Using higher values is untested. ---------------------------------------------------- 0x289 (Wax) 0x28A (Water) 0x28B (Vinegar) 0x28C (Root) 0x28D (Oil) 0x28E (Mushroom) 0x28F (Mud Pepper) 0x290 (Meteorite) 0x291 (Limestone) 0x292 (Iron) 0x293 (Gunpowder) 0x294 (Grease) 0x295 (Feather) 0x296 (Ethanol) 0x297 (Dry Ice) 0x298 (Crystal) 0x299 (Clay) 0x29A (Brimstone) 0x29B (Bone) 0x29C (Atlas Medallion) 0x29D (Ash) 0x29E (Acorn) ---------------------------------------------------- The next offsets are for the alchemy inventory. Just like the weapon inventory, the first value is the offset and the second is the bit that controls it. A set bit means you know the alchemy, and a clear bit means you don't. ---------------------------------------------------- 0x1F7 bit 0 (Acid Rain) 0x1F7 bit 1 (Atlas) 0x1F7 bit 2 (Barrier) 0x1F7 bit 3 (Call up) 0x1F7 bit 4 (Corrosion) 0x1F7 bit 5 (Crush) 0x1F7 bit 6 (Cure) 0x1F7 bit 7 (Defend) 0x1F8 bit 0 (Double Drain) 0x1F8 bit 1 (Drain) 0x1F8 bit 2 (Energize) 0x1F8 bit 3 (Escape) 0x1F8 bit 4 (Explosion) 0x1F8 bit 5 (Fireball) 0x1F8 bit 6 (Fire Power) 0x1F8 bit 7 (Flash) 0x1F9 bit 0 (Force Field) 0x1F9 bit 1 (Hard Ball) 0x1F9 bit 2 (Heal) 0x1F9 bit 3 (Lance) 0x1F9 bit 4 (Laser - dummied alchemy) 0x1F9 bit 5 (Levitate) 0x1F9 bit 6 (Lightning Storm) 0x1F9 bit 7 (Miracle Cure) 0x1FA bit 0 (Nitro) 0x1FA bit 1 (One Up) 0x1FA bit 2 (Reflect) 0x1FA bit 3 (Regrowth) 0x1FA bit 4 (Revealer) 0x1FA bit 5 (Revive) 0x1FA bit 6 (Slow Burn) 0x1FA bit 7 (Speed) 0x1FB bit 0 (Sting) 0x1FB bit 1 (Stop) 0x1FB bit 2 (Super Heal) ---------------------------------------------------- The next set of offsets are for the alchemy levels. The first offset is their major level (0-9), and the second is their minor level (power-up progress). The minor level can range from 0-99. For some reason, both of these offsets are 2 bytes, but since the values never exceed 255, you can just ignore their second byte and treat them like a single byte value. ---------------------------------------------------- 0x19B 0x155 (Acid Rain) 0x19D 0x157 (Atlas) 0x19F 0x159 (Barrier) 0x1A1 0x15B (Call Up) 0x1A3 0x15D (Corrosion) 0x1A5 0x15F (Crush) 0x1A7 0x161 (Cure) 0x1A9 0x163 (Defend) 0x1AB 0x165 (Double Drain) 0x1AD 0x167 (Drain) 0x1AF 0x169 (Energize) 0x1B1 0x16B (Escape) 0x1B3 0x16D (Explosion) 0x1B5 0x16F (Fireball) 0x1B7 0x171 (Fire Power) 0x1B9 0x173 (Flash) 0x1BB 0x175 (Force Field) 0x1BD 0x177 (Hard Ball) 0x1BF 0x179 (Heal) 0x1C1 0x17B (Lance) 0x1C3 0x17D (Laser - dummied alchemy) 0x1C5 0x17F (Leviate) 0x1C7 0x181 (Lightning Storm) 0x1C9 0x183 (Miracle Cure) 0x1CB 0x185 (Nitro) 0x1CD 0x187 (One Up) 0x1CF 0x189 (Reflect) 0x1D1 0x18B (Regrowth) 0x1D3 0x18D (Revealer) 0x1D5 0x18F (Revive) 0x1D7 0x191 (Slow Burn) 0x1D9 0x193 (Speed) 0x1DB 0x195 (Sting) 0x1DD 0x197 (Stop) 0x1DF 0x199 (Super Heal) ---------------------------------------------------- The next offsets are for the inventory items, which include the common items, equipment, and trade goods. In other words, anything that can be bought, sold, or traded. Most items have a valid range of 0-6, but a few can be up to 99. These include call beads, bazooka ammunition, and all the trade goods. Using higher values is untested. ---------------------------------------------------- 0x29F (Petal) 0x2A0 (Nectar) 0x2A1 (Honey) 0x2A2 (Dog Biscuit) 0x2A3 (Wings) 0x2A4 (Essence) 0x2A5 (Pixie Dust) 0x2A6 (Call Bead) 0x2A7 (Grass Vest) 0x2A8 (Shell Plate) 0x2A9 (Dino Skin) 0x2AA (Bronze Armor) 0x2AB (Stone Vest) 0x2AC (Centurion Cape) 0x2AD (Silver Mail) 0x2AE (Gold Plated Vest) 0x2AF (Shining Armor) 0x2B0 (Magna Mail) 0x2B1 (Titanium Vest) 0x2B2 (Virtual Vest) 0x2B3 (Grass Hat) 0x2B4 (Shell Hat) 0x2B5 (Dino Helm) 0x2B6 (Bronze Helmet) 0x2B7 (Obsidian Helm) 0x2B8 (Centurion Helm) 0x2B9 (Titan's Crown) 0x2BA (Dragon Helm) 0x2BB (Knight's Helm) 0x2BC (Lightning Helm) 0x2BD (Old Reliable) 0x2BE (Brainstorm) 0x2BF (Vine Bracelet) 0x2C0 (Mammoth Guard) 0x2C1 (Claw Guard) 0x2C2 (Serpent Bracer) 0x2C3 (Bronze Gauntlet) 0x2C4 (Gloves of Ra) 0x2C5 (Iron Bracer) 0x2C6 (Magician's Ring) 0x2C7 (Dragon's Claw) 0x2C8 (Cyberglove) 0x2C9 (Protector Ring) 0x2CA (Virtual Glove) 0x2CB (Leather Collar) 0x2CC (Spiky Collar) 0x2CD (Defender Collar) 0x2CE (Spot's Collar) 0x2CF (Thunderball) 0x2D0 (Particle Bomb) 0x2D1 (Cryo-Blast) 0x315 (Annihilation Amulet) 0x316 (Beads) 0x317 (Ceramic Pot) 0x318 (Chicken) 0x319 (Golden Jackal) 0x31A (Jeweled Scarab) 0x31B (Limestone Tablet) 0x31C (Perfume) 0x31D (Rice) 0x31E (Spice) 0x31F (Souvenir Spoon) 0x320 (Tapestry) 0x321 (Ticket for Exhibition) ---------------------------------------------------- The final offsets are for the charms. They are just like the weapon and alchemy inventories. The first value is the offset, and the second is the controlling bit. ---------------------------------------------------- 0x200 bit 5 (Armor Polish) 0x200 bit 6 (Chocobo Egg) 0x200 bit 7 (Insect Incense) 0x201 bit 0 (Jade Disk) 0x201 bit 1 (Jaguar Ring) 0x201 bit 2 (Magic Gourd) 0x201 bit 3 (Moxa Stick) 0x201 bit 4 (Oracle Bone) 0x201 bit 5 (Ruby Heart) 0x201 bit 6 (Silver Sheath) 0x201 bit 7 (Staff of Life) 0x202 bit 0 (Sun Stone) 0x202 bit 1 (Thug's Cloak) 0x202 bit 2 (Wizard's Coin) ---------------------------------------------------- The remaining values in the SRAM are unknown. Please contact me if there you think I have missed something important. ------------------------------------------------------------------------------- | 4.3 The Sanity Algorithm ------------------------------------------------------------------------------- As described earlier, Secret of Evermore uses two bytes of sanity data to ensure the SRAM is still being saved by the battery. This section describes that algorithm. The following is the actual algorithm in the US version, obtained using Geiger's Snes9x debugger. I have commented each line. --------------------------------------------------------------------- $8D/B469 A0 2F 03 LDY #$032F ; load 0x32F into counter $8D/B46C 22 78 B4 8D JSL $8DB478[$8D:B478] ; jump to subroutine $8D/B478 A9 3F 04 LDA #$043F ; a = 0x43F $8D/B47B E2 20 SEP #$20 ; use 8-bit accumulator $8D/B47D 18 CLC ; clear carry $8D/B47E 7D 00 00 ADC $0000,x[$30:6666] ; add data[offset] $8D/B481 88 DEY ; y = y - 1 $8D/B482 F0 0B BEQ $0B [$B48F] ; branch if y = 0 $8D/B484 E8 INX ; x = x + 1 $8D/B485 C2 20 REP #$20 ; use 16-bit accumulator $8D/B487 0A ASL A ; shift left $8D/B488 E2 20 SEP #$20 ; use 8-bit accumulator $8D/B48A 7D 00 00 ADC $0000,x[$30:6667] ; add data[offset] $8D/B48D 80 F2 BRA $F2 [$B481] ; branch always $8D/B48F C2 20 REP #$20 ; use 16-bit accumulator $8D/B491 6B RTL ; return from subroutine --------------------------------------------------------------------- The SNES used a custom WDC 65c816 processor, so if you wanted to learn more about this code, that's the assembly language it's in. The algorithm is fairly straightforward. First, we take an accumulator and initialize it with 0x043F. The first byte of game data is added to the lower byte of our accumulator. If a carry results, we ignore it. Next we start a loop. We shift the accumulator left by 1. The shifted bit is placed in the carry. Then we add the next byte of data to the lower byte of our accumulator. The carry is also added here and reset to 0. If our addition results in a carry, it will be placed in the carry. This process is repeated for every byte of game data. Note that the carry from our addition will be ignored due to the shift that always occurs following the next iteration of the loop. In the European versions, the algorithm is only slightly different. Change the initial value 0x43F to 0x16FF. This is the only difference. When you edit the SRAM by hand, the checksum will be wrong. To get around this, you will need to fix the checksum. If you try to skip the sanity check with a game genie code, and have invalid game data in any of the four slots, the game is quite likely to crash. The following is a listing for a C program which will fix the sanity data for an SRAM file. -------------------------------- soe-sanity.c --------------------------------- /* * Secret of Evermore Sanity Fixer * Copyright (C) 2006,2008 emuWorks * http://games.technoplaza.net/ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include // define this at compile time on big endian systems (i.e. PPC Mac's) #ifdef BYTE_ORDER_BIGENDIAN #define SWAP_ON_BIGENDIAN(w) ((w << 8) | (w >> 8)) #else #define SWAP_ON_BIGENDIAN(w) (w) #endif struct options { int game, version; const char *filename; }; static void fix_game(unsigned char *sram, int game, unsigned long checksum) { unsigned short *offset = (unsigned short *)(sram + 2 + (game * 0x331)); unsigned char temp = checksum + sram[4 + (game * 0x331)]; int i; for (i = 3; i < 0x331; ++i) { checksum &= 0xFF00; checksum |= temp; checksum <<= 1; if (checksum > 0xFFFF) checksum -= 0xFFFF; temp = checksum + sram[2 + i + (game * 0x331)]; } *offset = SWAP_ON_BIGENDIAN(checksum); } static void parse_command_line(int argc, char **argv, struct options *opts) { int i; opts->filename = argv[1]; opts->game = 1; opts->version = 0; for (i = 1; i < argc; ++i) { if (strcmp(argv[i], "--game") == 0) { if (++i < argc) { switch (*argv[i]) { case '2': opts->game = 2; break; case '3': opts->game = 3; break; case '4': opts->game = 4; break; default: opts->game = 1; } } } else if (strcmp(argv[i], "--version") == 0) { if (++i < argc) { if (strcmp(argv[i], "europe") == 0) opts->version = 1; else opts->version = 0; } } else { opts->filename = argv[i]; } } } int main(int argc, char **argv) { FILE *f; struct options opts; char sram[0x2000]; if (argc < 3) { fprintf(stderr, "syntax: soe-sanity sram-file.srm " "[ --game 1-4 ] [ --version us | europe ]\n"); return -1; } parse_command_line(argc, argv, &opts); if ((f = fopen(opts.filename, "rb")) == NULL) { fprintf(stderr, "error: unable to open SRAM file '%s'\n", argv[1]); return -1; } fseek(f, 0, SEEK_END); if (ftell(f) != 0x2000) { fprintf(stderr, "error: invalid SRAM file size.\n"); return -1; } fseek(f, 0, SEEK_SET); if (fread(sram, 0x2000, 1, f) != 1) { fprintf(stderr, "error: unable to read SRAM file.\n"); return -1; } fclose(f); fix_game(sram, (opts.game - 1), ((opts.version == 0) ? 0x43F : 0x16FF)); if ((f = fopen(opts.filename, "wb")) == NULL) { fprintf(stderr, "error: unable to open SRAM file '%s'\n", argv[1]); return -1; } if (fwrite(sram, 0x2000, 1, f) != 1) { fprintf(stderr, "error: unable to write SRAM data to file.\n"); return -1; } fclose(f); printf("fixed checksum for game %d in file %s (%s version)\n", opts.game, opts.filename, ((opts.version == 0) ? "us" : "european")); return 0; } ------------------------------------------------------------------------------- There is a windows binary available at http://games.technoplaza.net/soesrame/history/soe-sanity.zip. For other platforms, you will need to compile it yourself. It is written in standard ANSI C, so it should run anywhere. If you are compiling on a big endian platform, you will need to define BYTE_ORDER_BIGENDIAN at compile time. PowerPC and Sparc machines are probably the most common big endian platforms. Intel machines (x86) are little endian. gcc -o soe-sanity soe-sanity.c Will build the program using gcc on a little endian platform. gcc -DBYTE_ORDER_BIGENDIAN -o soe-sanity soe-sanity.c Will build the program using gcc on a big endian machine. I don't have much experience with compilers other than gcc, so you'll have to figure it out yourself if you're using something else. The program has a simple interface. Specify the sram filename, the game that needs fixing, and the version of the game (us or europe). It defaults to game 1 and the US version. Examples: soe-sanity "Secret of Evermore (U).srm" soe-sanity "Secret of Evermore (G).srm" --game 2 --version europe The first one fixes the checksum for the first game using the US algorithm. The second one fixes the checksum for the second game using the European algorithm. ------------------------------------------------------------------------------- | 5.0 soesrame - Secret of Evermore SRAM Editor ------------------------------------------------------------------------------- For those that don't want to play around with the SRAM directly, I have written a program that edits all the values documented here. It's also nice in that it keeps the values within their valid ranges, and handles the sanity data for you. You can find it at http://games.technoplaza.net/soesrame/. There are binaries for Windows, Mac OS X, and Linux. It should work on any platform that supports Qt, so it should work on any unice with X Windows. The full source is available as well. ------------------------------------------------------------------------------- | 6.0 Credits & Acknowledgements ------------------------------------------------------------------------------- I want to thank phonymike for discovering and documenting the checksum algorithm used by Secret of Evermore. He was also very helpful in answering questions I had about his code. Thanks to Geiger for his debugging Snes9x version and the entire Snes9x team for Snes9x. Without it, it would have been very difficult to find the SRAM offsets. ------------------------------------------------------------------------------- | 7.0 Contact Information ------------------------------------------------------------------------------- The author (John Ratliff) can be contacted at webmaster [AT] technoplaza [DOT] net. Replace as necessary. I can also be reached via an online feedback form at http://www.technoplaza.net/feedback.php