00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifdef HAVE_CONFIG_H
00026 #include <config.h>
00027 #endif
00028
00029 #include <cstring>
00030
00031 #include "model/ModelConstants.hh"
00032 #include "model/SaveSlot.hh"
00033
00034 using namespace hack4u;
00035
00036 const std::pair<int, int> hack4u::FOUND_RUNES_OFFSET[] = {
00037 std::pair<int, int>(0xD4, 4), std::pair<int, int>(0xD4, 5),
00038 std::pair<int, int>(0xD4, 6), std::pair<int, int>(0xD4, 7),
00039 std::pair<int, int>(0xD5, 0), std::pair<int, int>(0xD5, 1),
00040 std::pair<int, int>(0xD5, 2), std::pair<int, int>(0xD5, 3)
00041 };
00042
00043 const std::pair<int, int> hack4u::FOUND_STONES_OFFSET[] = {
00044 std::pair<int, int>(0xD6, 7), std::pair<int, int>(0xD7, 0),
00045 std::pair<int, int>(0xD7, 1), std::pair<int, int>(0xD7, 2),
00046 std::pair<int, int>(0xD7, 3), std::pair<int, int>(0xD7, 4),
00047 std::pair<int, int>(0xD7, 5), std::pair<int, int>(0xD7, 6)
00048 };
00049
00050 const std::pair<int, int> hack4u::FOUND_BELL_OFFSET(0xD6, 1);
00051 const std::pair<int, int> hack4u::FOUND_BOOK_OFFSET(0xD6, 0);
00052 const std::pair<int, int> hack4u::FOUND_CANDLE_OFFSET(0xD5, 7);
00053 const std::pair<int, int> hack4u::FOUND_FLUTE_OFFSET(0xD5, 5);
00054 const std::pair<int, int> hack4u::FOUND_HORN_OFFSET(0xD6, 3);
00055 const std::pair<int, int> hack4u::FOUND_SCALE_OFFSET(0xD5, 4);
00056 const std::pair<int, int> hack4u::FOUND_SKULL_OFFSET(0xD6, 4);
00057
00058 const int SaveSlot::CHECKSUM_XORS[] = {
00059 0x55, 0xAA, 0x33, 0xCC,
00060 0xA5, 0x5A, 0xBB, 0x99
00061 };
00062
00063 SaveSlot::SaveSlot(const char *data) {
00064 nvram = new unsigned char[SAVE_SIZE];
00065 std::memcpy(nvram, data, SAVE_SIZE);
00066
00067 setModified(false);
00068 }
00069
00070 SaveSlot::~SaveSlot() {
00071 delete nvram;
00072 }
00073
00074 std::pair<int, int> SaveSlot::getBalloonLocation() const {
00075 return std::pair<int, int>(nvram[BALLOON_LATITUDE_OFFSET],
00076 nvram[BALLOON_LONGITUDE_OFFSET]);
00077 }
00078
00079 void SaveSlot::setBalloonLocation(std::pair<int, int> location) {
00080 nvram[BALLOON_LATITUDE_OFFSET] = location.first;
00081 nvram[BALLOON_LONGITUDE_OFFSET] = location.second;
00082
00083 setModified();
00084 }
00085
00086 wxInt16 SaveSlot::getCurrentHP(enum Character character) const {
00087 wxInt16 *ptr = reinterpret_cast<wxInt16 *>
00088 (nvram + CURRENT_HP_OFFSET + (character * 2));
00089
00090 return wxINT16_SWAP_ON_BE(ptr[0]);
00091 }
00092
00093 void SaveSlot::setCurrentHP(enum Character character, wxInt16 value) {
00094 wxInt16 *ptr = reinterpret_cast<wxInt16 *>
00095 (nvram + CURRENT_HP_OFFSET + (character * 2));
00096
00097 ptr[0] = wxINT16_SWAP_ON_BE(value);
00098 setModified();
00099 }
00100
00101 int SaveSlot::getCurrentMP(enum Character character) const {
00102 return nvram[CURRENT_MP_OFFSET + character];
00103 }
00104
00105 void SaveSlot::setCurrentMP(enum Character character, unsigned char value) {
00106 nvram[CURRENT_MP_OFFSET + character] = value;
00107 setModified();
00108 }
00109
00110 int SaveSlot::getDexterity(enum Character character) const {
00111 return nvram[DEXTERITY_OFFSET + character];
00112 }
00113
00114 void SaveSlot::setDexterity(enum Character character, unsigned char value) {
00115 nvram[DEXTERITY_OFFSET + character] = value;
00116 setModified();
00117 }
00118
00119 int SaveSlot::getEquipment(enum Character character, int slot) const {
00120 return nvram[EQUIPMENT_OFFSET + (character * 6) + slot];
00121 }
00122
00123 void SaveSlot::setEquipment(enum Character character,
00124 int slot, unsigned char value) {
00125 nvram[EQUIPMENT_OFFSET + (character * 6) + slot] = value;
00126 setModified();
00127 }
00128
00129 wxInt16 SaveSlot::getExperience(enum Character character) const {
00130 wxInt16 *ptr = reinterpret_cast<wxInt16 *>
00131 (nvram + EXPERIENCE_OFFSET + (character * 2));
00132
00133 return wxINT16_SWAP_ON_BE(ptr[0]);
00134 }
00135
00136 void SaveSlot::setExperience(enum Character character, wxInt16 value) {
00137 wxInt16 *ptr = reinterpret_cast<wxInt16 *>
00138 (nvram + EXPERIENCE_OFFSET + (character * 2));
00139
00140 ptr[0] = wxINT16_SWAP_ON_BE(value);
00141 setModified();
00142 }
00143
00144 wxInt16 SaveSlot::getGold() const {
00145 wxUint16 *ptr = reinterpret_cast<wxUint16 *>(nvram + GOLD_OFFSET);
00146
00147 return wxINT16_SWAP_ON_BE(ptr[0]);
00148 }
00149
00150 void SaveSlot::setGold(wxInt16 gold) {
00151 wxUint16 *ptr = reinterpret_cast<wxUint16 *>(nvram + GOLD_OFFSET);
00152
00153 ptr[0] = wxINT16_SWAP_ON_BE(gold);
00154 setModified();
00155 }
00156
00157 int SaveSlot::getHerb(enum Herb herb) const {
00158 return nvram[HERB_OFFSET + herb];
00159 }
00160
00161 void SaveSlot::setHerb(enum Herb herb, unsigned char value) {
00162 nvram[HERB_OFFSET + herb] = value;
00163 setModified();
00164 }
00165
00166 wxString SaveSlot::getHerosName() const {
00167 wxString name;
00168
00169 for (int offset = NAME_OFFSET; offset <= (NAME_OFFSET + 5); ++offset) {
00170 if (nvram[offset] == 0) {
00171 break;
00172 }
00173
00174 char letter = fromNES(nvram[offset]);
00175 name.append(1, letter);
00176 }
00177
00178 return name;
00179 }
00180
00181 void SaveSlot::setHerosName(const wxString &name) {
00182 int pos;
00183 int length = name.size();
00184
00185 for (pos = 0; pos < 5; ++pos) {
00186 if ((length - 1) < pos) {
00187 nvram[NAME_OFFSET + pos] = 0;
00188 } else {
00189 nvram[NAME_OFFSET + pos] = toNES(name.at(pos));
00190 }
00191 }
00192
00193 setModified();
00194 }
00195
00196 int SaveSlot::getIntelligence(enum Character character) const {
00197 return nvram[INTELLIGENCE_OFFSET + character];
00198 }
00199
00200 void SaveSlot::setIntelligence(enum Character character, unsigned char value) {
00201 nvram[INTELLIGENCE_OFFSET + character] = value;
00202 setModified();
00203 }
00204
00205 bool SaveSlot::hasJoined(enum Character character) const {
00206 return (nvram[JOINED_OFFSET] & (1 << character));
00207 }
00208
00209 void SaveSlot::setJoined(enum Character character, bool value) {
00210 int mask = 1 << character;
00211
00212 if (value) {
00213 nvram[JOINED_OFFSET] |= mask;
00214 } else {
00215 nvram[JOINED_OFFSET] &= ~mask;
00216 }
00217
00218 setModified();
00219 }
00220
00221 int SaveSlot::getLevel(enum Character character) const {
00222 return nvram[LEVEL_OFFSET + character];
00223 }
00224
00225 void SaveSlot::setLevel(enum Character character, unsigned char level) {
00226 nvram[LEVEL_OFFSET + character] = level;
00227 setModified();
00228 }
00229
00230 bool SaveSlot::hasMagic(enum Magic magic) const {
00231 int offset = MAGIC_OFFSET;
00232 int temp = magic;
00233
00234 if (temp > 7) {
00235 offset += (temp / 8);
00236 temp %= 8;
00237 }
00238
00239 return (nvram[offset] & (1 << temp));
00240 }
00241
00242 void SaveSlot::setMagic(enum Magic magic, bool give) {
00243
00244 wxASSERT((magic != INVALID1) && (magic != INVALID2) && (magic != INVALID3));
00245
00246 int offset = MAGIC_OFFSET;
00247 int temp = magic;
00248
00249 if (temp > 7) {
00250 offset += (temp / 8);
00251 temp %= 8;
00252 }
00253
00254 int mask = 1 << temp;
00255
00256 if (give) {
00257 nvram[offset] |= mask;
00258 } else {
00259 nvram[offset] &= ~mask;
00260 }
00261
00262 setModified();
00263 }
00264
00265 wxInt16 SaveSlot::getMaxHP(enum Character character) const {
00266 wxInt16 *ptr = reinterpret_cast<wxInt16 *>
00267 (nvram + MAX_HP_OFFSET + (character * 2));
00268
00269 return wxINT16_SWAP_ON_BE(ptr[0]);
00270 }
00271
00272 void SaveSlot::setMaxHP(enum Character character, wxInt16 value) {
00273 wxInt16 *ptr = reinterpret_cast<wxInt16 *>
00274 (nvram + MAX_HP_OFFSET + (character * 2));
00275
00276 ptr[0] = wxINT16_SWAP_ON_BE(value);
00277 setModified();
00278 }
00279
00280 int SaveSlot::getMaxMP(enum Character character) const {
00281 return nvram[MAX_MP_OFFSET + character];
00282 }
00283
00284 void SaveSlot::setMaxMP(enum Character character, unsigned char value) {
00285 nvram[MAX_MP_OFFSET + character] = value;
00286 setModified();
00287 }
00288
00289 int SaveSlot::getMember(int position) const {
00290 return (nvram[MEMBER_OFFSET + position]);
00291 }
00292
00293 void SaveSlot::setMember(int position, int character) {
00294 nvram[MEMBER_OFFSET + position] = character;
00295 setModified();
00296 }
00297
00298 void SaveSlot::setModified(bool modified) {
00299 this->modified = modified;
00300
00301 if (modified) {
00302 nvram[CHECKSUM_OFFSET] = checksum();
00303 }
00304 }
00305
00306 int SaveSlot::getPhase(enum Moon moon) const {
00307 int phase = nvram[MOON_OFFSET];
00308
00309 if (moon == TRAMMEL) {
00310 return (phase / 3);
00311 }
00312
00313 return (phase % 3);
00314 }
00315
00316 void SaveSlot::setPhase(enum City trammel, int felucca) {
00317 int phase = (trammel * 3) + felucca;
00318
00319 nvram[MOON_OFFSET] = phase;
00320 setModified();
00321 }
00322
00323 bool SaveSlot::hasPirateShip(enum PirateShip ship) const {
00324 return (nvram[PIRATESHIP_OFFSET] & (1 << ship));
00325 }
00326
00327 void SaveSlot::setPirateShip(enum PirateShip ship, bool give) {
00328 int mask = 1 << ship;
00329
00330 if (give) {
00331 nvram[PIRATESHIP_OFFSET] |= mask;
00332 } else {
00333 nvram[PIRATESHIP_OFFSET] &= ~mask;
00334 }
00335
00336 setModified();
00337 }
00338
00339 std::pair<int, int>
00340 SaveSlot::getPirateShipLocation(enum PirateShip ship) const {
00341 return std::pair<int, int>
00342 (nvram[PIRATESHIP_LATITUDE_OFFSET + (ship << 1)],
00343 nvram[PIRATESHIP_LONGITUDE_OFFSET + (ship << 1)]);
00344 }
00345
00346 void SaveSlot::setPirateShipLocation(enum PirateShip ship,
00347 std::pair<int, int> location) {
00348 nvram[PIRATESHIP_LATITUDE_OFFSET + (ship << 1)] = location.first;
00349 nvram[PIRATESHIP_LONGITUDE_OFFSET + (ship << 1)] = location.second;
00350
00351 setModified();
00352 }
00353
00354 bool SaveSlot::hasRune(enum Virtue rune) const {
00355 return (nvram[RUNES_OFFSET] & (1 << rune));
00356 }
00357
00358 void SaveSlot::setRune(enum Virtue rune, bool give) {
00359 const std::pair<int, int> &found = FOUND_RUNES_OFFSET[rune];
00360
00361 if (give) {
00362 nvram[RUNES_OFFSET] |= (1 << rune);
00363 nvram[found.first] |= (1 << found.second);
00364 } else {
00365 nvram[RUNES_OFFSET] &= ~(1 << rune);
00366 nvram[found.first] &= ~(1 << found.second);
00367 }
00368
00369 setModified();
00370 }
00371
00372 enum StartLocation SaveSlot::getStartLocation() const {
00373 return static_cast<enum StartLocation>(nvram[START_LOCATION]);
00374 }
00375
00376 void SaveSlot::setStartLocation(enum StartLocation location) {
00377 nvram[START_LOCATION] = location;
00378 setModified();
00379 }
00380
00381 bool SaveSlot::hasStone(enum Virtue stone) const {
00382 return (nvram[STONES_OFFSET] & (1 << stone));
00383 }
00384
00385 void SaveSlot::setStone(enum Virtue stone, bool give) {
00386 const std::pair<int, int> &found = FOUND_STONES_OFFSET[stone];
00387
00388 if (give) {
00389 nvram[STONES_OFFSET] |= (1 << stone);
00390 nvram[found.first] |= (1 << found.second);
00391 } else {
00392 nvram[STONES_OFFSET] &= ~(1 << stone);
00393 nvram[found.first] &= ~(1 << found.second);
00394 }
00395
00396 setModified();
00397 }
00398
00399 int SaveSlot::getStrength(enum Character character) const {
00400 return nvram[STRENGTH_OFFSET + character];
00401 }
00402
00403 void SaveSlot::setStrength(enum Character character, unsigned char value) {
00404 nvram[STRENGTH_OFFSET + character] = value;
00405 setModified();
00406 }
00407
00408 int SaveSlot::getTool(enum Tool tool) const {
00409 return nvram[TOOL_OFFSET + tool];
00410 }
00411
00412 void SaveSlot::setTool(enum Tool tool, unsigned char value) {
00413 nvram[TOOL_OFFSET + tool] = value;
00414
00415 const std::pair<int, int> *found = 0;
00416
00417 if (tool == BELL) {
00418 found = &FOUND_BELL_OFFSET;
00419 } else if (tool == BOOK) {
00420 found = &FOUND_BOOK_OFFSET;
00421 } else if (tool == CANDLE) {
00422 found = &FOUND_CANDLE_OFFSET;
00423 } else if (tool == FLUTE) {
00424 found = &FOUND_FLUTE_OFFSET;
00425 } else if (tool == HORN) {
00426 found = &FOUND_HORN_OFFSET;
00427 } else if (tool == SCALE) {
00428 found = &FOUND_SCALE_OFFSET;
00429 } else if (tool == SKULL) {
00430 found = &FOUND_SKULL_OFFSET;
00431 }
00432
00433 if (found) {
00434 if (value > 0) {
00435 nvram[found->first] |= (1 << found->second);
00436 } else {
00437 nvram[found->first] &= ~(1 << found->second);
00438 }
00439 }
00440
00441 setModified();
00442 }
00443
00444 int SaveSlot::getVirtue(enum Virtue virtue) const {
00445 return nvram[VIRTUE_OFFSET + virtue];
00446 }
00447
00448 void SaveSlot::setVirtue(enum Virtue virtue, unsigned char value) {
00449 int mask = 1 << virtue;
00450
00451 if (value == 100) {
00452 nvram[AVATAR_OFFSET] |= mask;
00453 } else {
00454 nvram[AVATAR_OFFSET] &= ~mask;
00455 }
00456
00457 nvram[VIRTUE_OFFSET + virtue] = value;
00458 setModified();
00459 }
00460
00461 char SaveSlot::fromNES(unsigned char letter) {
00462 if ((letter >= 0x91) && (letter <= 0xAA)) {
00463 return ((letter - 0x91) + 'A');
00464 } else if ((letter >= 0xD1) && (letter <= 0xEA)) {
00465 return ((letter - 0xD1) + 'a');
00466 } else if (letter == 0xD0) {
00467 return '-';
00468 } else if (letter == 0x90) {
00469 return '!';
00470 }
00471
00472
00473 return '_';
00474 }
00475
00476 unsigned char SaveSlot::toNES(char letter) {
00477 if ((letter >= 'A') && (letter <= 'Z')) {
00478 return (unsigned char)(0x91 + (letter - 'A'));
00479 } else if ((letter >= 'a') && (letter <= 'z')) {
00480 return (unsigned char)(0xD1 + (letter - 'a'));
00481 } else if (letter == '-') {
00482 return (unsigned char)0xD0;
00483 } else if (letter == '!') {
00484 return (unsigned char)0x90;
00485 }
00486
00487
00488 return (unsigned char)0xBC;
00489 }
00490
00491 std::pair<int, int> SaveSlot::getWhirlpoolLocation() const {
00492 return std::pair<int, int>(nvram[WHIRLPOOL_LATITUDE_OFFSET],
00493 nvram[WHIRLPOOL_LONGITUDE_OFFSET]);
00494 }
00495
00496 void SaveSlot::setWhirlpoolLocation(std::pair<int, int> location) {
00497 nvram[WHIRLPOOL_LATITUDE_OFFSET] = location.first;
00498 nvram[WHIRLPOOL_LONGITUDE_OFFSET] = location.second;
00499
00500 setModified();
00501 }
00502
00503 unsigned char SaveSlot::checksum() const {
00504 unsigned char sum = 0;
00505 int index = 0;
00506
00507 for (int i = 1; i < SAVE_SIZE; ++i) {
00508 sum += (nvram[i] ^ CHECKSUM_XORS[index]);
00509
00510 ++index &= 0x7;
00511 }
00512
00513 return sum;
00514 }
00515