sramfile.cc

Go to the documentation of this file.
00001 /*
00002  * Secret of Evermore SRAM Editor
00003  * Copyright (C) 2006 emuWorks
00004  * http://games.technoplaza.net/
00005  *
00006  * This file is part of Secret of Evermore SRAM Editor.
00007  *
00008  * Secret of Evermore SRAM Editor is free software; you can redistribute it
00009  * and/or modify it under the terms of the GNU General Public License as
00010  * published by the Free Software Foundation; either version 2 of the License,
00011  * or (at your option) any later version.
00012  *
00013  * Secret of Evermore SRAM Editor is distributed in the hope that it will be
00014  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with Secret of Evermore SRAM Editor; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00021  */
00022  
00023 // $Id: sramfile.cc,v 1.23 2006/09/10 05:04:52 technoplaza Exp $
00024 
00025 #include <cstring>
00026 #include <fstream>
00027 
00028 #include <QtCore/qendian.h>
00029 
00030 #include "model/sramfile.hh"
00031 
00032 using namespace soesrame;
00033 
00034 const std::pair<int, int> SRAMFile::SRAM_ALCHEMY_OFFSETS[] =
00035     {
00036         std::pair<int, int>(0x1F7, 0x01),  // acid rain
00037         std::pair<int, int>(0x1F7, 0x02),  // atlas
00038         std::pair<int, int>(0x1F7, 0x04),  // barrier
00039         std::pair<int, int>(0x1F7, 0x08),  // call up
00040         std::pair<int, int>(0x1F7, 0x10),  // corrosion
00041         std::pair<int, int>(0x1F7, 0x20),  // crush
00042         std::pair<int, int>(0x1F7, 0x40),  // cure
00043         std::pair<int, int>(0x1F7, 0x80),  // defend
00044         
00045         std::pair<int, int>(0x1F8, 0x01),  // double drain
00046         std::pair<int, int>(0x1F8, 0x02),  // drain
00047         std::pair<int, int>(0x1F8, 0x04),  // energize
00048         std::pair<int, int>(0x1F8, 0x08),  // escape
00049         std::pair<int, int>(0x1F8, 0x10),  // explosion
00050         std::pair<int, int>(0x1F8, 0x20),  // fireball
00051         std::pair<int, int>(0x1F8, 0x40),  // fire power
00052         std::pair<int, int>(0x1F8, 0x80),  // flash
00053         
00054         std::pair<int, int>(0x1F9, 0x01),  // force field
00055         std::pair<int, int>(0x1F9, 0x02),  // hard ball
00056         std::pair<int, int>(0x1F9, 0x04),  // heal
00057         std::pair<int, int>(0x1F9, 0x08),  // lance
00058         std::pair<int, int>(0x1F9, 0x10),  // laser (dummied spell)
00059         std::pair<int, int>(0x1F9, 0x20),  // levitate
00060         std::pair<int, int>(0x1F9, 0x40),  // lightning storm
00061         std::pair<int, int>(0x1F9, 0x80),  // miracle cure
00062         
00063         std::pair<int, int>(0x1FA, 0x01),  // nitro
00064         std::pair<int, int>(0x1FA, 0x02),  // one up
00065         std::pair<int, int>(0x1FA, 0x04),  // reflect
00066         std::pair<int, int>(0x1FA, 0x08),  // regrowth
00067         std::pair<int, int>(0x1FA, 0x10),  // revealer
00068         std::pair<int, int>(0x1FA, 0x20),  // revive
00069         std::pair<int, int>(0x1FA, 0x40),  // slow burn
00070         std::pair<int, int>(0x1FA, 0x80),  // speed
00071         
00072         std::pair<int, int>(0x1FB, 0x01),  // sting
00073         std::pair<int, int>(0x1FB, 0x02),  // stop
00074         std::pair<int, int>(0x1FB, 0x04)   // super heal
00075     };
00076     
00077 const std::pair<int, int> SRAMFile::SRAM_CHARM_OFFSETS[] =
00078     {
00079         std::pair<int, int>(0x200, 0x20),   // armor polish
00080         std::pair<int, int>(0x200, 0x40),   // chocobo egg
00081         std::pair<int, int>(0x200, 0x80),   // insect incense
00082         
00083         std::pair<int, int>(0x201, 0x01),   // jade disk
00084         std::pair<int, int>(0x201, 0x02),   // jaguar ring
00085         std::pair<int, int>(0x201, 0x04),   // magic gourd
00086         std::pair<int, int>(0x201, 0x08),   // moxa stick
00087         std::pair<int, int>(0x201, 0x10),   // oracle bone
00088         std::pair<int, int>(0x201, 0x20),   // ruby heart
00089         std::pair<int, int>(0x201, 0x40),   // silver sheath
00090         std::pair<int, int>(0x201, 0x80),   // staff of life
00091         
00092         std::pair<int, int>(0x202, 0x01),   // sun stone
00093         std::pair<int, int>(0x202, 0x02),   // thug's cloak
00094         std::pair<int, int>(0x202, 0x04)    // wizard's coin
00095     };
00096     
00097 const std::pair<int, int> SRAMFile::SRAM_WEAPON_OFFSETS[] =
00098     {
00099         std::pair<int, int>(0x279, 0x02),  // bone crusher
00100         std::pair<int, int>(0x279, 0x04),  // gladiator sword
00101         std::pair<int, int>(0x279, 0x08),  // crusader sword
00102         std::pair<int, int>(0x279, 0x10),  // neutron blade
00103         
00104         std::pair<int, int>(0x279, 0x20),  // spider's claw
00105         std::pair<int, int>(0x279, 0x40),  // bronze axe
00106         std::pair<int, int>(0x279, 0x80),  // knight basher
00107         std::pair<int, int>(0x27A, 0x01),  // atom smasher
00108         
00109         std::pair<int, int>(0x27A, 0x02),  // horn spear
00110         std::pair<int, int>(0x27A, 0x04),  // bronze spear
00111         std::pair<int, int>(0x27A, 0x08),  // lance
00112         std::pair<int, int>(0x27A, 0x10),  // laser lance
00113         
00114         std::pair<int, int>(0x27A, 0x20)   // bazooka
00115     };
00116 
00117 SRAMFile::SRAMFile(const QString &filename) throw(InvalidSRAMFileException)
00118     : modified(false) {
00119     std::ifstream file(filename.toAscii().data(), 
00120                        std::ios_base::in | std::ios_base::binary);
00121     
00122     if (!file) {
00123         throw InvalidSRAMFileException(ISFE_FILENOTFOUND);
00124     }
00125     
00126     file.seekg(0, std::ios_base::end);
00127     
00128     if (file.tellg() != static_cast<std::streampos>(SRAM_FILE_SIZE)) {
00129         throw InvalidSRAMFileException(ISFE_INVALIDSIZE);
00130     }
00131     
00132     file.seekg(0, std::ios_base::beg);
00133     file.read(reinterpret_cast<char *>(sram), SRAM_FILE_SIZE);
00134     file.close();
00135     
00136     bool valid = false;
00137     
00138     for (int game = 3; game >= 0; --game) {
00139         if (checksum(game) == getChecksum(game)) {
00140             valid = true;
00141             this->valid[game] = true;
00142             setGame(game);
00143         }
00144     }
00145     
00146     if (!valid) {
00147         throw InvalidSRAMFileException(ISFE_NOVALIDGAMES);
00148     }
00149 }
00150 
00151 quint16 SRAMFile::checksum(int game) const {
00152     quint32 checksum = 0x43F;
00153     unsigned char temp = checksum +
00154                          sram[SRAM_GAME_OFFSET + 2 + game * SRAM_GAME_SIZE];
00155     
00156     for (int i = 3; i < SRAM_GAME_SIZE; ++i) {
00157         checksum &= 0xFF00;
00158         checksum |= temp;
00159         checksum <<= 1;
00160         
00161         if (checksum > 0xFFFF) {
00162             checksum -= 0xFFFF;
00163         }
00164         
00165         temp = checksum + sram[SRAM_GAME_OFFSET + i + game * SRAM_GAME_SIZE];
00166     }
00167     
00168     return static_cast<quint16>(checksum);
00169 }
00170 
00171 bool SRAMFile::save(const QString &filename) {
00172     for (int game = 0; game < 4; ++game) {
00173         if (isValid(game)) {
00174             setChecksum(game, checksum(game));
00175         }
00176     }
00177     
00178     std::ofstream file(filename.toAscii().data(),
00179                        std::ios_base::out | std::ios_base::binary);
00180     
00181     if (!file) {
00182         return false;
00183     }
00184     
00185     file.write(reinterpret_cast<char *>(sram), SRAM_FILE_SIZE);
00186     
00187     if (file.tellp() != static_cast<std::streampos>(SRAM_FILE_SIZE)) {
00188         return false;
00189     }
00190     
00191     file.close();
00192     modified = false;
00193     
00194     return true;
00195 }
00196 
00197 bool SRAMFile::hasAlchemy(enum sf_alchemy alchemy) const {
00198     Q_ASSERT(isValid(getGame()));
00199     
00200     return (offset[SRAM_ALCHEMY_OFFSETS[alchemy].first] &
00201             SRAM_ALCHEMY_OFFSETS[alchemy].second);
00202 }
00203 
00204 void SRAMFile::setAlchemy(enum sf_alchemy alchemy, bool have) {
00205     Q_ASSERT(isValid(getGame()));
00206     
00207     unsigned char *data = offset + SRAM_ALCHEMY_OFFSETS[alchemy].first;
00208     
00209     if (have) {
00210         *data |= SRAM_ALCHEMY_OFFSETS[alchemy].second;
00211     } else {
00212         *data &= ~SRAM_ALCHEMY_OFFSETS[alchemy].second;
00213     }
00214     
00215     modified = true;
00216 }
00217 
00218 std::pair<int, int> SRAMFile::getAlchemyLevel(enum sf_alchemy alchemy) const {
00219     Q_ASSERT(isValid(getGame()));
00220     
00221     return std::pair<int, int>
00222         (offset[SRAM_ALCHEMYMAJORLEVELS_OFFSET + (alchemy * 2)],
00223          offset[SRAM_ALCHEMYMINORLEVELS_OFFSET + (alchemy * 2)]); 
00224 }
00225 
00226 void SRAMFile::setAlchemyLevel(enum sf_alchemy alchemy,
00227                                std::pair<int, int> level) {
00228     Q_ASSERT(isValid(getGame()));
00229     Q_ASSERT((level.first >= 0) && (level.first < 10));
00230     Q_ASSERT((level.second >= 0) && (level.second < 100));
00231     
00232     offset[SRAM_ALCHEMYMAJORLEVELS_OFFSET + (alchemy * 2)] = level.first;
00233     offset[SRAM_ALCHEMYMINORLEVELS_OFFSET + (alchemy * 2)] = level.second;
00234     
00235     modified = true;
00236 }
00237 
00238 std::pair<int, int> SRAMFile::getAttackLevel() const {
00239     Q_ASSERT(isValid(getGame()));
00240     
00241     return std::pair<int, int>
00242         (offset[SRAM_DOG_ATTACKLEVEL_OFFSET + 1],
00243          offset[SRAM_DOG_ATTACKLEVEL_OFFSET]);
00244 }
00245 
00246 void SRAMFile::setAttackLevel(std::pair<int, int> level) {
00247     Q_ASSERT(isValid(getGame()));
00248     Q_ASSERT((level.first >= 1) && (level.first < 4));
00249     Q_ASSERT((level.second >= 0) && (level.second < 256));
00250     
00251     offset[SRAM_DOG_ATTACKLEVEL_OFFSET + 1] = level.first;
00252     offset[SRAM_DOG_ATTACKLEVEL_OFFSET] = level.second;
00253     
00254     modified = true;
00255 }
00256 
00257 bool SRAMFile::hasCharm(enum sf_charm charm) const {
00258     Q_ASSERT(isValid(getGame()));
00259     
00260     return (offset[SRAM_CHARM_OFFSETS[charm].first] &
00261             SRAM_CHARM_OFFSETS[charm].second);
00262 }
00263 
00264 void SRAMFile::setCharm(enum sf_charm charm, bool have) {
00265     Q_ASSERT(isValid(getGame()));
00266     
00267     unsigned char *data = offset + SRAM_CHARM_OFFSETS[charm].first;
00268     
00269     if (have) {
00270         *data |= SRAM_CHARM_OFFSETS[charm].second;
00271     } else {
00272         *data &= ~SRAM_CHARM_OFFSETS[charm].second;
00273     }
00274     
00275     modified = true;
00276 }
00277 
00278 quint16 SRAMFile::getChecksum(int game) const {
00279     const quint16 *data =
00280         reinterpret_cast<const quint16 *>(sram + SRAM_GAME_OFFSET +
00281                                           game * SRAM_GAME_SIZE +
00282                                           SRAM_CHECKSUM_OFFSET);
00283     
00284     return qFromLittleEndian(*data);
00285 }
00286 
00287 void SRAMFile::setChecksum(int game, quint16 checksum) {
00288     quint16 *data = reinterpret_cast<quint16 *>(sram + SRAM_GAME_OFFSET +
00289                                                 game * SRAM_GAME_SIZE +
00290                                                 SRAM_CHECKSUM_OFFSET);
00291     
00292     *data = qToLittleEndian(checksum);
00293 }
00294 
00295 quint16 SRAMFile::getCurrentHP(enum sf_hero hero) const {
00296     Q_ASSERT(isValid(getGame()));
00297     
00298     const quint16 *data =
00299         reinterpret_cast<const quint16 *>(offset +
00300                                           ((hero == SF_BOY) ?
00301                                            SRAM_BOY_CURRENTHP_OFFSET :
00302                                            SRAM_DOG_CURRENTHP_OFFSET));
00303                                       
00304     return qFromLittleEndian(*data);
00305 }
00306 
00307 void SRAMFile::setCurrentHP(enum sf_hero hero, quint16 hp) {
00308     Q_ASSERT(isValid(getGame()));
00309     Q_ASSERT((hp >= 0) && (hp < 1000));
00310     
00311     quint16 *data = reinterpret_cast<quint16 *>(offset +
00312                                                 ((hero == SF_BOY) ?
00313                                                  SRAM_BOY_CURRENTHP_OFFSET :
00314                                                  SRAM_DOG_CURRENTHP_OFFSET));
00315                                                  
00316     *data = qToLittleEndian(hp);
00317     modified = true;
00318 }
00319 
00320 quint32 SRAMFile::getExperience(enum sf_hero hero) const {
00321     Q_ASSERT(isValid(getGame()));
00322     
00323     const quint32 *data =
00324         reinterpret_cast<const quint32 *>(offset +
00325                                           ((hero == SF_BOY) ?
00326                                            SRAM_BOY_EXPERIENCE_OFFSET :
00327                                            SRAM_DOG_EXPERIENCE_OFFSET));
00328                                            
00329     return (qFromLittleEndian(*data) & 0xFFFFFF);
00330 }
00331 
00332 void SRAMFile::setExperience(enum sf_hero hero, quint32 experience) {
00333     Q_ASSERT(isValid(getGame()));
00334     Q_ASSERT((experience >= 0) && (experience < 16777216));
00335     
00336     unsigned char *data = offset + ((hero == SF_BOY) ?
00337                                     SRAM_BOY_EXPERIENCE_OFFSET :
00338                                     SRAM_DOG_EXPERIENCE_OFFSET);
00339     
00340     data[0] = experience;
00341     data[1] = experience >> 8;
00342     data[2] = experience >> 16;
00343     
00344     modified = true;
00345 }
00346 
00347 void SRAMFile::setGame(int game) {
00348     Q_ASSERT((game >= 0) && (game < 4));
00349     
00350     this->game = game;
00351     offset = sram + SRAM_GAME_OFFSET + (game * SRAM_GAME_SIZE);
00352 }
00353 
00354 int SRAMFile::getIngredient(enum sf_ingredient ingredient) const {
00355     Q_ASSERT(isValid(getGame()));
00356     
00357     return offset[SRAM_INGREDIENTS_OFFSET + ingredient];
00358 }
00359 
00360 void SRAMFile::setIngredient(enum sf_ingredient ingredient, int count) {
00361     Q_ASSERT(isValid(getGame()));
00362     Q_ASSERT((count >= 0) && (count < 100));
00363     
00364     offset[SRAM_INGREDIENTS_OFFSET + ingredient] = count;
00365     modified = true;
00366 }
00367 
00368 int SRAMFile::getItem(enum sf_item item) const {
00369     Q_ASSERT(isValid(getGame()));
00370     
00371     return offset[SRAM_ITEMS_OFFSET + item];
00372 }
00373 
00374 void SRAMFile::setItem(enum sf_item item, int count) {
00375     Q_ASSERT(isValid(getGame()));
00376     Q_ASSERT((count >= 0) && (count < 100));
00377     
00378     offset[SRAM_ITEMS_OFFSET + item] = count;
00379     modified = true;
00380 }
00381 
00382 int SRAMFile::getLevel(enum sf_hero hero) const {
00383     Q_ASSERT(isValid(getGame()));
00384     
00385     return offset[((hero == SF_BOY) ?
00386                    SRAM_BOY_LEVEL_OFFSET :
00387                    SRAM_DOG_LEVEL_OFFSET)];
00388 }
00389 
00390 void SRAMFile::setLevel(enum sf_hero hero, int level) {
00391     Q_ASSERT(isValid(getGame()));
00392     Q_ASSERT((level >= 1) && (level < 100));
00393     
00394     offset[((hero == SF_BOY) ?
00395             SRAM_BOY_LEVEL_OFFSET :
00396             SRAM_DOG_LEVEL_OFFSET)] = level;
00397     modified = true;
00398 }
00399 
00400 quint16 SRAMFile::getMaxHP(enum sf_hero hero) const {
00401     Q_ASSERT(isValid(getGame()));
00402     
00403     const quint16 *data =
00404         reinterpret_cast<const quint16 *>(offset +
00405                                           ((hero == SF_BOY) ?
00406                                            SRAM_BOY_MAXHP_OFFSET :
00407                                            SRAM_DOG_MAXHP_OFFSET));
00408                                       
00409     return qFromLittleEndian(*data);
00410 }
00411 
00412 void SRAMFile::setMaxHP(enum sf_hero hero, quint16 hp) {
00413     Q_ASSERT(isValid(getGame()));
00414     Q_ASSERT((hp >= 0) && (hp < 1000));
00415     
00416     quint16 *data = reinterpret_cast<quint16 *>(offset +
00417                                                 ((hero == SF_BOY) ?
00418                                                  SRAM_BOY_MAXHP_OFFSET :
00419                                                  SRAM_DOG_MAXHP_OFFSET));
00420                                                  
00421     *data = qToLittleEndian(hp);
00422     modified = true;
00423 }
00424 
00425 quint32 SRAMFile::getMoney(enum sf_money money) const {
00426     Q_ASSERT(isValid(getGame()));
00427     
00428     const quint32 *data =
00429         reinterpret_cast<const quint32 *>(offset +
00430                                           SRAM_MONEY_OFFSET + (money * 3));
00431                                           
00432     return (qFromLittleEndian(*data) & 0xFFFFFF);
00433 }
00434 
00435 void SRAMFile::setMoney(enum sf_money money, quint32 count) {
00436     Q_ASSERT(isValid(getGame()));
00437     Q_ASSERT((count >= 0) && (count < 16777216));
00438     
00439     unsigned char *data = offset + SRAM_MONEY_OFFSET + (money * 3);
00440     
00441     data[0] = count;
00442     data[1] = count >> 8;
00443     data[2] = count >> 16;
00444     
00445     modified = true;
00446 }
00447 
00448 QString SRAMFile::getName(enum sf_hero hero) const {
00449     Q_ASSERT(isValid(getGame()));
00450     
00451     const char *data =
00452         reinterpret_cast<const char *>(offset +
00453                                        ((hero == SF_BOY) ?
00454                                         SRAM_BOY_NAME_OFFSET :
00455                                         SRAM_DOG_NAME_OFFSET));
00456                                                
00457     return QString::fromAscii(data);
00458 }
00459 
00460 void SRAMFile::setName(enum sf_hero hero, const QString &name) {
00461     Q_ASSERT(isValid(getGame()));
00462     Q_ASSERT(name.length() <= 15);
00463     
00464     char *data = reinterpret_cast<char *>(offset + ((hero == SF_BOY) ?
00465                                                     SRAM_BOY_NAME_OFFSET :
00466                                                     SRAM_DOG_NAME_OFFSET));
00467                                                     
00468     std::strcpy(data, name.left(15).toAscii().data());
00469     
00470     modified = true;
00471 }
00472 
00473 quint16 SRAMFile::getTradeGood(enum sf_tradegood tradegood) const {
00474     Q_ASSERT(isValid(getGame()));
00475     
00476     const quint16 *data =
00477         reinterpret_cast<const quint16 *>(offset + SRAM_TRADEGOODS_OFFSET);
00478     
00479     return qFromLittleEndian(data[tradegood]);
00480 }
00481 
00482 void SRAMFile::setTradeGood(enum sf_tradegood tradegood, quint16 count) {
00483     Q_ASSERT(isValid(getGame()));
00484     Q_ASSERT((count >= 0) && (count < 100));
00485     
00486     quint16 *data =
00487         reinterpret_cast<quint16 *>(offset + SRAM_TRADEGOODS_OFFSET);
00488     
00489     data[tradegood] = qToLittleEndian(count);
00490     modified = true;
00491 }
00492 
00493 bool SRAMFile::hasWeapon(enum sf_weapon weapon) const {
00494     Q_ASSERT(isValid(getGame()));
00495     
00496     return (offset[SRAM_WEAPON_OFFSETS[weapon].first] &
00497             SRAM_WEAPON_OFFSETS[weapon].second);
00498 }
00499 
00500 void SRAMFile::setWeapon(enum sf_weapon weapon, bool have) {
00501     Q_ASSERT(isValid(getGame()));
00502     
00503     unsigned char *data = offset + SRAM_WEAPON_OFFSETS[weapon].first;
00504     
00505     if (have) {
00506         *data |= SRAM_WEAPON_OFFSETS[weapon].second;
00507     } else {
00508         *data &= ~SRAM_WEAPON_OFFSETS[weapon].second;
00509     }
00510     
00511     modified = true;
00512 }
00513 
00514 std::pair<int, int> SRAMFile::getWeaponLevel(enum sf_weapon weapon) const {
00515     Q_ASSERT(isValid(getGame()));
00516     Q_ASSERT(weapon != SF_BAZOOKA);
00517     
00518     const unsigned char *data =
00519         offset + SRAM_WEAPONLEVELS_OFFSET + (weapon * 2);
00520     
00521     return std::pair<int, int>(data[1], data[0]);
00522 }
00523 
00524 void SRAMFile::setWeaponLevel(enum sf_weapon weapon,
00525                               std::pair<int, int> level) {
00526     Q_ASSERT(isValid(getGame()));
00527     Q_ASSERT(weapon != SF_BAZOOKA);
00528     Q_ASSERT((level.first >= 1) && (level.first < 4));
00529     Q_ASSERT((level.second >= 0) && (level.second < 256));
00530     
00531     unsigned char *data = offset + SRAM_WEAPONLEVELS_OFFSET + (weapon * 2);
00532     
00533     data[1] = level.first;
00534     data[0] = level.second;
00535     
00536     modified = true;
00537 }
00538 

Generated on Sun Sep 10 01:49:26 2006 for Secret of Evermore SRAM Editor by  doxygen 1.4.7