sramfile.cc

Go to the documentation of this file.
00001 /*
00002  * dwsrame - Dragon Warrior SRAM Editor
00003  * Copyright (C) 2006-2008 emuWorks
00004  * http://games.technoplaza.net/
00005  *
00006  * This file is part of dwsrame.
00007  *
00008  * dwsrame is free software; you can redistribute it and/or modify it under the
00009  * terms of the GNU General Public License as published by the Free Software
00010  * Foundation; either version 2 of the License, or (at your option) any later
00011  * version.
00012  *
00013  * dwsrame is distributed in the hope that it will be useful, but WITHOUT ANY
00014  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
00015  * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License along with
00018  * dwsrame; if not, write to the Free Software Foundation, Inc.,
00019  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020  */
00021 
00022 // $Id: sramfile.cc,v 1.10 2008/12/15 22:48:11 jdratlif Exp $
00023 
00024 #ifdef HAVE_CONFIG_H
00025     #include <config.h>
00026 #endif
00027 
00028 #include <wx/wxprec.h>
00029 
00030 #ifndef WX_PRECOMP
00031     #include <wx/wx.h>
00032 #endif
00033 
00034 #include <cstring>
00035 #include <fstream>
00036 
00037 #include "model/sramfile.hh"
00038 
00039 using namespace dwsrame;
00040 
00041 const std::pair<int, int> SRAMFile::QUEST_OFFSETS[] =
00042     {
00043         std::pair<int, int>(0xB, 0x04), // charlock stairs
00044         std::pair<int, int>(0xB, 0x08), // rainbow bridge
00045         std::pair<int, int>(0xB, 0x10), // using dragon's scale
00046         std::pair<int, int>(0xB, 0x20), // using fighter's ring
00047         std::pair<int, int>(0xB, 0x40), // using cursed belt
00048         std::pair<int, int>(0xB, 0x80), // using death necklace
00049         
00050         std::pair<int, int>(0xC, 0x01), // holding gwaelin
00051         std::pair<int, int>(0xC, 0x02), // gwaelin on throne
00052         std::pair<int, int>(0xC, 0x08), // started quest
00053         
00054         std::pair<int, int>(0xD, 0x02), // golem
00055         std::pair<int, int>(0xD, 0x04), // dragonlord
00056         std::pair<int, int>(0xD, 0x40), // green dragon
00057     };
00058 
00059 SRAMFile::SRAMFile(const wxString &filename)
00060     throw(InvalidSRAMFileException) : modified(false) {
00061     std::ifstream file(filename.mb_str(),
00062                        std::ios_base::in | std::ios_base::binary);
00063     
00064     if (!file) {
00065         throw InvalidSRAMFileException(ISFE_FILENOTFOUND);
00066     }
00067     
00068     file.seekg(0, std::ios_base::end);
00069     
00070     if (file.tellg() != static_cast<std::streampos>(SRAM_SIZE)) {
00071         throw InvalidSRAMFileException(ISFE_INVALIDSIZE);
00072     }
00073     
00074     file.seekg(0, std::ios_base::beg);
00075     file.read(sram, SRAM_SIZE);
00076     file.close();
00077     
00078     // look for KEN MASUTA string
00079     if (std::strncmp("KEN MASUTA", (sram + KENMASUTA_OFFSET), 10) != 0) {
00080         throw InvalidSRAMFileException(ISFE_NOVALIDGAMES);
00081     }
00082     
00083     // checksum to determine valid games
00084     std::memset(valid, 0, 3 * sizeof(bool));
00085     
00086     bool foundValid = false;
00087     
00088     for (int game = 2; game >= 0; --game) {
00089         if (sram[SLOT_OFFSET + game] == MAGIC_NUMBER) {
00090             if (checksum(game) == getChecksum(game)) {
00091                 valid[game] = foundValid = true;
00092                 setGame(game);
00093             }
00094         }
00095     }
00096     
00097     if (!foundValid) {
00098         throw InvalidSRAMFileException(ISFE_NOVALIDGAMES);
00099     }
00100 }
00101 
00102 /*
00103     $FBEF:A0 1D     LDY #$1D        ; load counter with 0x1D
00104     $FBF1:84 94     STY $0094       ; init checksum low byte
00105     $FBF3:84 95     STY $0095       ; init checksum high byte
00106     $FBF5:B1 22     LDA ($22),Y     ; load data[counter] into a
00107     $FBF7:85 3C     STA $003C       ; store to memory
00108     $FBF9:20 2A FC  JSR $FC2A       ; jump to subroutine
00109     $FBFC:88        DEY             ; y = y - 1
00110     $FBFD:10 F6     BPL $FBF5       ; repeat 0x1D + 1 times
00111     $FBFF:60        RTS             ; end of checksum algorithm
00112 
00113     $FC2A:98        TYA             ; put counter into a
00114     $FC2B:48        PHA             ; push counter to stack
00115     $FC2C:A0 08     LDY #$08        ; load new counter with 8
00116     $FC2E:A5 95     LDA $0095       ; load checksum high byte
00117     $FC30:45 3C     EOR $003C       ; xor data[counter] with checksum high byte
00118     $FC32:06 94     ASL $0094       ; shift left checksum low byte
00119     $FC34:26 95     ROL $0095       ; rotate shifted bit onto checksum high byte
00120     $FC36:06 3C     ASL $003C       ; shift left data[counter]
00121     $FC38:0A        ASL             ; shift left original checksum high byte
00122     $FC39:90 0C     BCC $FC47       ; skip if shifted bit was 0
00123     $FC3B:A5 94     LDA $0094       ; load checksum low byte
00124     $FC3D:49 21     EOR #$21        ; xor checksum low byte with 0x21
00125     $FC3F:85 94     STA $0094       ; store into checksum low byte
00126     $FC41:A5 95     LDA $0095       ; load checksum high byte
00127     $FC43:49 10     EOR #$10        ; xor checksum high with 0x10
00128     $FC45:85 95     STA $0095       ; store checksum high byte
00129     $FC47:88        DEY             ; y = y - 1
00130     $FC48:D0 E4     BNE $FC2E       ; repeat 8 times
00131     $FC4A:68        PLA             ; pull counter from stack
00132     $FC4B:A8        TAY             ; restore counter to y
00133     $FC4C:60        RTS             ; return
00134 */
00135 
00136 wxUint16 SRAMFile::checksum(int game) const {
00137     wxASSERT((game >= 0) && (game < 3));
00138     
00139     unsigned char cl = 0x1D, ch = 0x1D, carry = 0;
00140     unsigned char al, bl, temp;
00141     
00142     for (int i = 0x1D; i >= 0; --i) {
00143         al = sram[GAME_OFFSET + (game * GAME_SIZE) + i];
00144         
00145         for (int j = 8; j > 0; --j) {
00146             bl = al ^ ch;
00147             
00148             // asl cl
00149             carry = (cl & 0x80) ? 1 : 0;
00150             cl <<= 1;
00151             
00152             // rol ch
00153             temp = (ch & 0x80) ? 1 : 0;
00154             ch = (ch << 1) | carry;
00155             carry = temp;
00156             
00157             // asl al
00158             carry = (al & 0x80) ? 1 : 0;
00159             al <<= 1;
00160             
00161             // asl bl
00162             carry = (bl & 0x80) ? 1 : 0;
00163             bl <<= 1;
00164             
00165             if (carry) {
00166                 cl ^= 0x21;
00167                 ch ^= 0x10;
00168             }
00169         }
00170     }
00171     
00172     return (cl | (ch << 8));
00173 }
00174 
00175 char SRAMFile::fromASCII(char asciiChar) const {
00176     char ch;
00177     
00178     switch (asciiChar) {
00179         case '0': case '1': case '2': case '3': case '4': case '5': case '6':
00180         case '7': case '8': case '9':
00181             ch = static_cast<char>(asciiChar - '0');
00182             break;
00183             
00184         case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
00185         case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
00186         case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
00187         case 'v': case 'w': case 'x': case 'y': case 'z':
00188             ch = static_cast<char>(asciiChar - 'a' + 0xA);
00189             break;
00190             
00191         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
00192         case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
00193         case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
00194         case 'V': case 'W': case 'X': case 'Y': case 'Z':
00195             ch = static_cast<char>(asciiChar - 'A' + 0x24);
00196             break;
00197             
00198         case '\'': ch = 0x40; break;
00199         case '.': ch = 0x47; break;
00200         case ',': ch = 0x48; break;
00201         case '-': ch = 0x49; break;
00202         case '?': ch = 0x4B; break;
00203         case '!': ch = 0x4C; break;
00204         case ')': ch = 0x4E; break;
00205         case '(': ch = 0x4F; break;
00206         case ' ': ch = 0x60; break;
00207         
00208         default:
00209             // we should NEVER reach the default case
00210             wxASSERT(false);
00211             
00212             ch = 0x60;
00213             break;
00214     }
00215     
00216     return ch;
00217 }
00218 
00219 bool SRAMFile::save(const wxString &filename) {
00220     std::ofstream file(filename.mb_str(),
00221                        std::ios_base::out | std::ios_base::binary);
00222     
00223     if (!file) {
00224         return false;
00225     }
00226     
00227     for (int i = 0; i < 3; ++i) {
00228         setChecksum(i, checksum(i));
00229     }
00230     
00231     file.write(sram, SRAM_SIZE);
00232     file.close();
00233     
00234     modified = false;
00235     
00236     return true;
00237 }
00238 
00239 char SRAMFile::toASCII(char dwChar) const {
00240     char ch;
00241     
00242     switch (dwChar) {
00243         case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8:
00244         case 9:
00245             ch = static_cast<char>('0' + dwChar);
00246             break;
00247             
00248         case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17:
00249         case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25:
00250         case 26: case 27: case 28: case 29: case 30: case 31: case 32: case 33:
00251         case 34: case 35:
00252             ch = static_cast<char>('a' + dwChar - 0xA);
00253             break;
00254             
00255         case 36: case 37: case 38: case 39: case 40: case 41: case 42: case 43:
00256         case 44: case 45: case 46: case 47: case 48: case 49: case 50: case 51:
00257         case 52: case 53: case 54: case 55: case 56: case 57: case 58: case 59:
00258         case 60: case 61:
00259             ch = static_cast<char>('A' + dwChar - 0x24);
00260             break;
00261             
00262         case 0x40: ch = '\''; break;
00263         case 0x47: ch = '.'; break;
00264         case 0x48: ch = ','; break;
00265         case 0x49: ch = '-'; break;
00266         case 0x4B: ch = '?'; break;
00267         case 0x4C: ch = '!'; break;
00268         case 0x4E: ch = ')'; break;
00269         case 0x4F: ch = '('; break;
00270         case 0x60: ch = ' '; break;
00271             
00272         default:
00273             // we should NEVER get to the default case
00274             wxASSERT(false);
00275             
00276             ch = '_';
00277             break;
00278     }
00279     
00280     return ch;
00281 }
00282 
00283 void SRAMFile::setArmor(enum dw_armor armor) {
00284     unsigned char *ptr =
00285         reinterpret_cast<unsigned char *>(offset + EQUIPMENT_OFFSET);
00286     
00287     *ptr &= ~ARMOR_MASK;
00288     *ptr |= armor;
00289     
00290     modified = true;
00291 }
00292 
00293 wxUint16 SRAMFile::getChecksum(int game) const {
00294     wxASSERT((game >= 0) && (game < 3));
00295     
00296     const wxUint16 *ptr = reinterpret_cast<const wxUint16 *>
00297         (sram + GAME_OFFSET + (GAME_SIZE * game) + CHECKSUM_OFFSET);
00298         
00299     return wxUINT16_SWAP_ON_BE(*ptr);
00300 }
00301 
00302 void SRAMFile::setChecksum(int game, wxUint16 checksum) {
00303     wxASSERT((game >= 0) && (game < 3));
00304     
00305     wxUint16 *ptr = reinterpret_cast<wxUint16 *>
00306         (sram + GAME_OFFSET + (GAME_SIZE * game) + CHECKSUM_OFFSET);
00307         
00308     *ptr = wxUINT16_SWAP_ON_BE(checksum);
00309 }
00310 
00311 wxUint16 SRAMFile::getExperience() const {
00312     const wxUint16 *ptr = reinterpret_cast<const wxUint16 *>
00313         (offset + EXP_OFFSET);
00314         
00315     return wxUINT16_SWAP_ON_BE(*ptr);
00316 }
00317 
00318 void SRAMFile::setExperience(wxUint16 experience) {
00319     wxUint16 *ptr = reinterpret_cast<wxUint16 *>(offset + EXP_OFFSET);
00320     
00321     *ptr = wxUINT16_SWAP_ON_BE(experience);
00322     
00323     modified = true;
00324 }
00325 
00326 void SRAMFile::setGame(int game) {
00327     wxASSERT((game >= 0) && (game < 3));
00328     wxASSERT(isValid(game));
00329     
00330     this->game = game;
00331     offset = reinterpret_cast<unsigned char *>
00332         (sram + GAME_OFFSET + (GAME_SIZE * game));
00333 }
00334 
00335 wxUint16 SRAMFile::getGold() const {
00336     const wxUint16 *ptr = reinterpret_cast<const wxUint16 *>
00337         (offset + GOLD_OFFSET);
00338         
00339     return wxUINT16_SWAP_ON_BE(*ptr);
00340 }
00341 
00342 void SRAMFile::setGold(wxUint16 gold) {
00343     wxUint16 *ptr = reinterpret_cast<wxUint16 *>(offset + GOLD_OFFSET);
00344     
00345     *ptr = wxUINT16_SWAP_ON_BE(gold);
00346     
00347     modified = true;
00348 }
00349 
00350 void SRAMFile::setHerbs(int herbs) {
00351     offset[HERBS_OFFSET] = herbs;
00352     modified = true;
00353 }
00354 
00355 void SRAMFile::setHP(unsigned int hp) {
00356     offset[HP_OFFSET] = hp;
00357     modified = true;
00358 }
00359 
00360 enum dw_item SRAMFile::getItem(int number) const {
00361     unsigned char value =
00362         static_cast<unsigned char>(*(offset + ITEM_OFFSET + (number / 2)));
00363         
00364     if ((number % 2) == 1) {
00365         value >>= 4;
00366     }
00367     
00368     return static_cast<enum dw_item>(value & 0xF);
00369 }
00370 
00371 void SRAMFile::setItem(enum dw_item item, int number) {
00372     unsigned char value = item;
00373     unsigned char *ptr =
00374         reinterpret_cast<unsigned char *>(offset + ITEM_OFFSET + (number / 2));
00375         
00376     if ((number % 2) == 1) {
00377         value <<= 4;
00378         *ptr &= 0xF;
00379     } else {
00380         *ptr &= 0xF0;
00381     }
00382     
00383     *ptr |= value;
00384     
00385     modified = true;
00386 }
00387 
00388 void SRAMFile::setKeys(int keys) {
00389     offset[KEYS_OFFSET] = keys;
00390     modified = true;
00391 }
00392 
00393 void SRAMFile::setMP(unsigned int mp) {
00394     offset[MP_OFFSET] = mp;
00395     modified = true;
00396 }
00397 
00398 wxString SRAMFile::getName() const {
00399     wxString name;
00400     const char *ptr = reinterpret_cast<const char *>(offset + NAME_OFFSET);
00401     
00402     for (int i = 0; i < 2; ++i) {
00403         for (int j = 3; j >= 0; --j) {
00404             name.Append(toASCII(ptr[j]));
00405         }
00406         
00407         ptr += 4;
00408     }
00409     
00410     return name.Trim();
00411 }
00412 
00413 void SRAMFile::setName(const wxString &name) {
00414     char *ptr = reinterpret_cast<char *>(offset + NAME_OFFSET);
00415     unsigned int count = 0;
00416     
00417     for (int i = 0; i < 2; ++i) {
00418         for (int j = 3; j >= 0; --j) {
00419             if (count < name.Length()) {
00420                 ptr[j] = fromASCII(name[count]);
00421             } else {
00422                 ptr[j] = fromASCII(' ');
00423             }
00424             
00425             ++count;
00426         }
00427         
00428         ptr += 4;
00429     }
00430     
00431     modified = true;
00432 }
00433 
00434 void SRAMFile::setQuestMarker(enum dw_quest marker, bool set) {
00435     if (set) {
00436         offset[QUEST_OFFSETS[marker].first] |= QUEST_OFFSETS[marker].second;
00437     } else {
00438         offset[QUEST_OFFSETS[marker].first] &= ~QUEST_OFFSETS[marker].second;
00439     }
00440     
00441     modified = true;
00442 }
00443 
00444 void SRAMFile::setShield(enum dw_shield shield) {
00445     unsigned char *ptr =
00446         reinterpret_cast<unsigned char *>(offset + EQUIPMENT_OFFSET);
00447     
00448     *ptr &= ~SHIELD_MASK;
00449     *ptr |= shield;
00450     
00451     modified = true;
00452 }
00453 
00454 void SRAMFile::setWeapon(enum dw_weapon weapon) {
00455     unsigned char *ptr =
00456         reinterpret_cast<unsigned char *>(offset + EQUIPMENT_OFFSET);
00457     
00458     *ptr &= ~WEAPON_MASK;
00459     *ptr |= weapon;
00460     
00461     modified = true;
00462 }
00463 

Generated on Mon Dec 29 00:46:09 2008 for Dragon Warrior SRAM Editor by  doxygen 1.5.4