* Start to fill in save related classes

* Fix silly bug in WiiSave
* Fix typos in Utilitiy.*
This commit is contained in:
Phillip Stephens 2014-11-28 19:32:37 -08:00
parent fea9a45a5c
commit be135d1caa
25 changed files with 476 additions and 122 deletions

View File

@ -49,7 +49,8 @@ SOURCES += \
$$PWD/src/LZ77/LZLookupTable.cpp \ $$PWD/src/LZ77/LZLookupTable.cpp \
$$PWD/src/LZ77/LZType10.cpp \ $$PWD/src/LZ77/LZType10.cpp \
$$PWD/src/LZ77/LZType11.cpp \ $$PWD/src/LZ77/LZType11.cpp \
$$PWD/src/LZ77/LZBase.cpp $$PWD/src/LZ77/LZBase.cpp \
$$PWD/src/Athena/MCSlot.cpp
win32:SOURCES += $$PWD/src/win32_largefilewrapper.c win32:SOURCES += $$PWD/src/win32_largefilewrapper.c
HEADERS += \ HEADERS += \
@ -111,7 +112,8 @@ HEADERS += \
$$PWD/include/LZ77/LZBase.hpp \ $$PWD/include/LZ77/LZBase.hpp \
$$PWD/include/LZ77/LZLookupTable.hpp \ $$PWD/include/LZ77/LZLookupTable.hpp \
$$PWD/include/LZ77/LZType10.hpp \ $$PWD/include/LZ77/LZType10.hpp \
$$PWD/include/LZ77/LZType11.hpp $$PWD/include/LZ77/LZType11.hpp \
$$PWD/src/Athena/MCSlot.hpp
win32:HEADERS += \ win32:HEADERS += \
$$PWD/include/win32_largefilewrapper.h $$PWD/include/win32_largefilewrapper.h

View File

@ -105,6 +105,10 @@ struct ALTTPLightDarkWorldIndicator
struct ALTTPDungeonItemFlags struct ALTTPDungeonItemFlags
{
union
{
struct
{ {
bool Unused1:1; bool Unused1:1;
bool Unused2:1; bool Unused2:1;
@ -114,14 +118,25 @@ struct ALTTPDungeonItemFlags
bool TowerOfHera:1; bool TowerOfHera:1;
bool IcePalace:1; bool IcePalace:1;
bool SkullWoods:1; bool SkullWoods:1;
};
atUint8 flags1;
};
union
{
struct
{
bool MiseryMire:1; bool MiseryMire:1;
bool DarkPalace:1; bool DarkPalace:1;
bool SwampPalace:1; bool SwampPalace:1;
bool HyruleCastle2:1; // Doesn't exists in orignal game bool HyruleCastle2:1; // unused in orignal game
bool DesertPalace:1; bool DesertPalace:1;
bool EasternPalace:1; bool EasternPalace:1;
bool HyruleCastle:1; // Doesn't exist in original game bool HyruleCastle:1; // unused exist in original game
bool SewerPassage:1; // Doesn't exist in original game bool SewerPassage:1; // unused exist in original game
};
atUint8 flags2;
};
}; };
struct ALTTPPendants struct ALTTPPendants

View File

@ -32,7 +32,7 @@ atInt32 compressZlib(const atUint8* src, atUint32 srcLen, atUint8* dst, atUint32
atInt32 decompressLZO(const atUint8* source, atInt32 sourceSize, atUint8* dst, atInt32& dstSize); atInt32 decompressLZO(const atUint8* source, atInt32 sourceSize, atUint8* dst, atInt32& dstSize);
// Yaz0 encoding // Yaz0 encoding
atUint32 yaz0Decode(const atUint8* src, atUint8*& dst, atUint32 uncompressedSize); atUint32 yaz0Decode(const atUint8* src, atUint8* dst, atUint32 uncompressedSize);
atUint32 yaz0Encode(const atUint8* src, atUint32 srcSize, atUint8* data); atUint32 yaz0Encode(const atUint8* src, atUint32 srcSize, atUint8* data);
atUint32 decompressLZ77(const atUint8* src, atUint32 srcLen, atUint8** dst); atUint32 decompressLZ77(const atUint8* src, atUint32 srcLen, atUint8** dst);

View File

@ -30,7 +30,7 @@
# elif defined(__func__) # elif defined(__func__)
# define __PRETTY_FUNCTION__ __func__ # define __PRETTY_FUNCTION__ __func__
# else # else
# define __PRETTY_FUNCTION__ "<unkown>" # define __PRETTY_FUNCTION__ "<unknown>"
# endif # endif
#endif #endif

View File

@ -16,9 +16,12 @@
#ifndef __MCFILE_HPP__ #ifndef __MCFILE_HPP__
#define __MCFILE_HPP__ #define __MCFILE_HPP__
#include "Athena/Global.hpp"
namespace Athena namespace Athena
{ {
class MCSlot;
/*! \class MCFile /*! \class MCFile
* \brief The Minish Cap data container class class * \brief The Minish Cap data container class class
* *
@ -28,8 +31,20 @@ namespace Athena
class MCFile class MCFile
{ {
public: public:
static constexpr char* VERSION_EU_JP = (char*)"AGBZELDA:THE MINISH CAP:ZELDA 3\0";
static constexpr char* VERSION_US = (char*)"AGBZELDA:THE MINISH CAP:ZELDA 5\0";
enum SlotType
{
New = 0x54494E49,
Valid = 0x4D435A33,
Deleted = 0x466C6544
};
MCFile(); MCFile();
static atUint8* unscramble(atUint8* data, atUint32 length);
private: private:
MCSlot* m_slots[3];
}; };
} // zelda } // zelda

View File

@ -34,7 +34,7 @@ namespace io
* all work is done using a memory buffer, and not read directly from the disk. * all work is done using a memory buffer, and not read directly from the disk.
* \sa BinaryReader * \sa BinaryReader
*/ */
class MCFileReader : protected BinaryReader class MCFileReader : public BinaryReader
{ {
BINARYREADER_BASE(); BINARYREADER_BASE();
public: public:

View File

@ -61,11 +61,9 @@ public:
*/ */
void writeFile(MCFile* file); void writeFile(MCFile* file);
static atUint16 calculateChecksum(atUint8* data, atUint32 length);
private: private:
atUint16 calculateSlotChecksum(atUint32 game); atUint16 calculateSlotChecksum(atUint32 game);
atUint16 calculateChecksum(atUint8* data, atUint32 length);
atUint8* reverse(atUint8* data, atUint32 length);
void unscramble();
}; };
} // io } // io

View File

@ -53,6 +53,7 @@ public:
void setRegion(Region region); void setRegion(Region region);
Region region() const; Region region() const;
private: private:
Region m_region; Region m_region;
// A vector is a bit overkill // A vector is a bit overkill

View File

@ -1,4 +1,4 @@
#if !defined(ATHENA_NO_SAVES) && !defined(ATHENA_NO_ZQUEST) #if !defined(ATHENA_NO_SAVES) && !defined(ATHENA_NO_ZQUEST)
// This file is part of libAthena. // This file is part of libAthena.
// //
// libAthena is free software: you can redistribute it and/or modify // libAthena is free software: you can redistribute it and/or modify
@ -27,17 +27,47 @@ namespace Athena
class SkywardSwordQuest : public ZQuestFile class SkywardSwordQuest : public ZQuestFile
{ {
public: public:
enum AmmoType
{
Arrows,
Bombs,
Seeds
};
SkywardSwordQuest(atUint8* data, atUint32 len); SkywardSwordQuest(atUint8* data, atUint32 len);
// TODO: Is len really needed? void setPlayerName(const std::string& name);
void setSkipData(const atUint8* data, atUint32 len = 0x24); std::string playerName() const;
void setRupeeCount(atUint16 value);
atUint16 rupeeCount();
void setAmmoCount(AmmoType type, atUint32 count);
atUint32 ammoCount(AmmoType type);
void setMaxHP(atUint16 val);
atUint16 maxHP();
float maxHearts();
void setSpawnHP(atUint16 val);
atUint16 spawnHP();
float spawnHearts();
void setCurrentHP(atUint16 val);
atUint16 currentHP();
float currentHearts();
std::string currentLocation();
std::string currentArea();
std::string currentLocationCopy();
void setSkipData(const atUint8* data);
atUint8* skipData() const; atUint8* skipData() const;
atUint32 skipLength() const;
atUint32 slotChecksum();
atUint32 skipChecksum();
void fixChecksums();
void setNew(bool isNew);
bool isNew() const;
private: private:
atUint8* m_skipData; atUint8* m_skipData;
atUint32 m_skipLength;
}; };

View File

@ -47,7 +47,7 @@ atUint32 BigUint32(atUint32& val);
atInt64 LittleInt64(atInt64& val); atInt64 LittleInt64(atInt64& val);
atUint64 LittleUint64(atUint64& val); atUint64 LittleUint64(atUint64& val);
atInt64 BigInt64(atInt64& val); atInt64 BigInt64(atInt64& val);
atUint16 BigUint64(atUint16& val); atUint64 BigUint64(atUint64& val);
float LittleFloat(float& val); float LittleFloat(float& val);
float BigFloat(float& val); float BigFloat(float& val);
@ -66,6 +66,14 @@ bool parseBool(const std::string& boolean, bool* valid = NULL);
int countChar(const std::string& str, const char chr, int* lastOccur = NULL); int countChar(const std::string& str, const char chr, int* lastOccur = NULL);
// trim from start
std::string &ltrim(std::string &s);
// trim from end
std::string &rtrim(std::string &s);
// trim from both ends
std::string &trim(std::string &s);
atUint64 fileSize(FILE* f); atUint64 fileSize(FILE* f);
} // utility } // utility
} // Athena } // Athena

View File

@ -58,7 +58,7 @@ public:
* \param filename * \param filename
* \param file * \param file
*/ */
void addFile(const std::string& filename, WiiFile* file); void addFile(WiiFile* file);
void setRoot(WiiFile* root); void setRoot(WiiFile* root);
/*! /*!
* \brief file * \brief file

View File

@ -152,7 +152,7 @@ public:
std::string gameString() const; std::string gameString() const;
static const std::vector<std::string> gameStringList(); static const std::vector<std::string> gameStringList();
private: protected:
Game m_game; Game m_game;
std::string m_gameString; std::string m_gameString;
Endian m_endian; Endian m_endian;

View File

@ -18,6 +18,7 @@
#include "Athena/ALTTPFile.hpp" #include "Athena/ALTTPFile.hpp"
#include "Athena/ALTTPQuest.hpp" #include "Athena/ALTTPQuest.hpp"
#include <iostream> #include <iostream>
#include "Athena/Global.hpp"
namespace Athena namespace Athena
{ {
@ -80,9 +81,9 @@ ALTTPFile* ALTTPFileReader::readFile()
quest->setHealthFiller(base::readByte()); quest->setHealthFiller(base::readByte());
quest->setMagicFiller(base::readByte()); quest->setMagicFiller(base::readByte());
ALTTPPendants pendants; ALTTPPendants pendants;
pendants.Courage = readBit(); pendants.Courage = base::readBit();
pendants.Wisdom = readBit(); pendants.Wisdom = base::readBit();
pendants.Power = readBit(); pendants.Power = base::readBit();
pendants.Unused1 = false; pendants.Unused1 = false;
pendants.Unused2 = false; pendants.Unused2 = false;
pendants.Unused3 = false; pendants.Unused3 = false;
@ -214,6 +215,7 @@ ALTTPDungeonItemFlags ALTTPFileReader::readDungeonFlags()
{ {
ALTTPDungeonItemFlags flags; ALTTPDungeonItemFlags flags;
flags.Unused1 = base::readBit(); flags.Unused1 = base::readBit();
flags.Unused2 = base::readBit();
flags.GanonsTower = base::readBit(); flags.GanonsTower = base::readBit();
flags.TurtleRock = base::readBit(); flags.TurtleRock = base::readBit();
flags.GargoylesDomain = base::readBit(); flags.GargoylesDomain = base::readBit();
@ -229,6 +231,7 @@ ALTTPDungeonItemFlags ALTTPFileReader::readDungeonFlags()
flags.HyruleCastle = base::readBit(); flags.HyruleCastle = base::readBit();
flags.SewerPassage = base::readBit(); flags.SewerPassage = base::readBit();
aDebug() << std::hex << flags.flags1 << " " << flags.flags2 << std::dec << std::endl;
return flags; return flags;
} }

View File

@ -542,12 +542,9 @@ std::vector<atUint16> ALTTPQuest::playerName() const
std::string ALTTPQuest::playerNameToString() const std::string ALTTPQuest::playerNameToString() const
{ {
std::string ret; std::string ret;
std::vector<atUint16>::const_iterator iter = m_playerName.begin();
for (; iter != m_playerName.end(); ++iter) for (atInt16 c : m_playerName)
{ {
atInt16 c = *iter;
if (c >= 0x00 && c <= 0x0F) if (c >= 0x00 && c <= 0x0F)
{ {
ret.push_back((char)('A' + c)); ret.push_back((char)('A' + c));

View File

@ -302,8 +302,10 @@ void BinaryWriter::writeInt16(atInt16 val)
if (m_position + sizeof(atInt16) > m_length) if (m_position + sizeof(atInt16) > m_length)
resize(m_position + sizeof(atInt16)); resize(m_position + sizeof(atInt16));
if ((!utility::isSystemBigEndian() && isBigEndian()) || (utility::isSystemBigEndian() && isLittleEndian())) if (isBigEndian())
val = utility::swap16(val); utility::BigInt16(val);
else
utility::LittleInt16(val);
*(atInt16*)(m_data + m_position) = val; *(atInt16*)(m_data + m_position) = val;
m_position += sizeof(atInt16); m_position += sizeof(atInt16);
@ -331,8 +333,10 @@ void BinaryWriter::writeInt32(atInt32 val)
if (m_position + sizeof(atInt32) > m_length) if (m_position + sizeof(atInt32) > m_length)
resize(m_position + sizeof(atInt32)); resize(m_position + sizeof(atInt32));
if ((!utility::isSystemBigEndian() && isBigEndian()) || (utility::isSystemBigEndian() && isLittleEndian())) if (isBigEndian())
val = utility::swap32(val); utility::BigInt32(val);
else
utility::LittleInt32(val);
*(atInt32*)(m_data + m_position) = val; *(atInt32*)(m_data + m_position) = val;
m_position += sizeof(atInt32); m_position += sizeof(atInt32);
@ -358,8 +362,10 @@ void BinaryWriter::writeInt64(atInt64 val)
resize(m_position + sizeof(atInt64)); resize(m_position + sizeof(atInt64));
if ((!utility::isSystemBigEndian() && isBigEndian()) || (utility::isSystemBigEndian() && isLittleEndian())) if (isBigEndian())
val = utility::swap64(val); utility::BigInt64(val);
else
utility::LittleInt64(val);
*(atInt64*)(m_data + m_position) = val; *(atInt64*)(m_data + m_position) = val;
m_position += sizeof(atInt64); m_position += sizeof(atInt64);
@ -376,8 +382,11 @@ void BinaryWriter::writeUint64(atUint64 val)
if (m_position + sizeof(atUint64) > m_length) if (m_position + sizeof(atUint64) > m_length)
resize(m_position + sizeof(atUint64)); resize(m_position + sizeof(atUint64));
if ((!utility::isSystemBigEndian() && isBigEndian()) || (utility::isSystemBigEndian() && isLittleEndian())) if (isBigEndian())
val = utility::swapU64(val); utility::BigUint64(val);
else
utility::LittleUint64(val);
*(atUint64*)(m_data + m_position) = val; *(atUint64*)(m_data + m_position) = val;
m_position += sizeof(atUint64); m_position += sizeof(atUint64);
@ -394,8 +403,11 @@ void BinaryWriter::writeFloat(float val)
if (m_position + sizeof(float) > m_length) if (m_position + sizeof(float) > m_length)
resize(m_position + sizeof(float)); resize(m_position + sizeof(float));
if ((!utility::isSystemBigEndian() && isBigEndian()) || (utility::isSystemBigEndian() && isLittleEndian())) if (isBigEndian())
val = utility::swapFloat(val); utility::BigFloat(val);
else
utility::LittleFloat(val);
*(float*)(m_data + m_position) = val; *(float*)(m_data + m_position) = val;
m_position += sizeof(float); m_position += sizeof(float);
@ -412,8 +424,10 @@ void BinaryWriter::writeDouble(double val)
if (m_position + sizeof(double) > m_length) if (m_position + sizeof(double) > m_length)
resize(m_position + sizeof(double)); resize(m_position + sizeof(double));
if ((!utility::isSystemBigEndian() && isBigEndian()) || (utility::isSystemBigEndian() && isLittleEndian())) if (isBigEndian())
val = utility::swapDouble(val); utility::BigDouble(val);
else
utility::LittleDouble(val);
*(double*)(m_data + m_position)= val; *(double*)(m_data + m_position)= val;
m_position += sizeof(double); m_position += sizeof(double);

View File

@ -22,4 +22,36 @@ MCFile::MCFile()
{ {
} }
// TODO: Rewrite this to be more optimized, the current solution takes quite a few cycles
atUint8* reverse(atUint8* data, atUint32 length)
{
atUint32 a = 0;
atUint32 swap;
for (;a<--length; a++)
{
swap = data[a];
data[a] = data[length];
data[length] = swap;
}
return data;
}
atUint8* MCFile::unscramble(atUint8* data, atUint32 length)
{
if (!data)
return nullptr;
for (atUint32 i = 0; i < length; i += 8)
{
atUint32 block1 = *(atUint32*)reverse((data + i), 4);
atUint32 block2 = *(atUint32*)reverse((data + i + 4), 4);
*(atUint32*)(data + i) = block2;
*(atUint32*)(data + i + 4) = block1;
}
return data;
}
} // zelda } // zelda

View File

@ -15,13 +15,14 @@
// along with libAthena. If not, see <http://www.gnu.org/licenses/> // along with libAthena. If not, see <http://www.gnu.org/licenses/>
#include "Athena/MCFileReader.hpp" #include "Athena/MCFileReader.hpp"
#include "Athena/MCFile.hpp"
namespace Athena namespace Athena
{ {
namespace io namespace io
{ {
static const atUint32 SCRAMBLE_VALUE = 0x5A424741;
MCFileReader::MCFileReader(atUint8* data, atUint64 length) MCFileReader::MCFileReader(atUint8* data, atUint64 length)
: base(data, length) : base(data, length)
{ {
@ -32,6 +33,16 @@ MCFileReader::MCFileReader(const std::string& filename)
{ {
} }
MCFile* MCFileReader::readFile()
{
bool isScrambled = base::readUint32() != SCRAMBLE_VALUE;
base::m_position = 0;
if (isScrambled)
MCFile::unscramble(base::m_data, base::m_length);
}
} // io } // io
} // zelda } // zelda
#endif // ATHENA_NO_SAVES #endif // ATHENA_NO_SAVES

View File

@ -64,38 +64,6 @@ atUint16 MCFileWriter::calculateChecksum(atUint8 *data, atUint32 length)
return sum; return sum;
} }
// TODO: Rewrite this to be more optimized, the current solution takes quite a few cycles
atUint8* MCFileWriter::reverse(atUint8* data, atUint32 length)
{
atUint32 a = 0;
atUint32 swap;
for (;a<--length; a++)
{
swap = data[a];
data[a] = data[length];
data[length] = swap;
}
return data;
}
// TODO: Rewrite this to be more optimized, unroll more??
void MCFileWriter::unscramble()
{
if (!m_data)
return;
for (atUint32 i = 0; i < m_length; i += 4)
{
atUint32 block1 = *(atUint32*)reverse((m_data + i), 4);
atUint32 block2 = *(atUint32*)reverse((m_data + i + 4), 4);
*(atUint32*)(m_data + i) = block2;
*(atUint32*)(m_data + i + 4) = block1;
}
}
} // io } // io
} // zelda } // zelda
#endif // ATHENA_NO_SAVES #endif // ATHENA_NO_SAVES

11
src/Athena/MCSlot.cpp Normal file
View File

@ -0,0 +1,11 @@
#include "MCSlot.hpp"
namespace Athena
{
MCSlot::MCSlot(atUint8* data, atUint32 length)
: ZQuestFile(ZQuestFile::MC, Endian::LittleEndian, data, length)
{
}
} // Athena

17
src/Athena/MCSlot.hpp Normal file
View File

@ -0,0 +1,17 @@
#ifndef MCSLOT_HPP
#define MCSLOT_HPP
#include "Athena/Global.hpp"
#include "Athena/ZQuestFile.hpp"
namespace Athena
{
class MCSlot : public ZQuestFile
{
public:
MCSlot(atUint8* data, atUint32 length);
};
} // Athena
#endif // MCSLOT_HPP

View File

@ -55,14 +55,14 @@ void SkywardSwordFileWriter::write(SkywardSwordFile *file)
{ {
if (q->length() != 0x53C0) if (q->length() != 0x53C0)
THROW_INVALID_DATA_EXCEPTION("q->data() not 0x53C0 bytes in length"); THROW_INVALID_DATA_EXCEPTION("q->data() not 0x53C0 bytes in length");
if (q->skipLength() != 0x24) // Update the checksums
THROW_INVALID_DATA_EXCEPTION("q->skipData() not 0x24 bytes in length"); q->fixChecksums();
// Write the save data // Write the save data
base::writeUBytes(q->data(), q->length()); base::writeUBytes(q->data(), q->length());
atUint64 pos = base::position(); atUint64 pos = base::position();
// Write the slots skip data // Write the slots skip data
base::seek(0xFB60 + (i * 0x24), SeekOrigin::Begin); base::seek(0xFB60 + (i * 0x24), SeekOrigin::Begin);
base::writeUBytes(q->skipData(), q->skipLength()); base::writeUBytes(q->skipData(), 0x24);
base::seek(pos, SeekOrigin::Begin); base::seek(pos, SeekOrigin::Begin);
i++; i++;
} }

View File

@ -15,17 +15,50 @@
// along with libAthena. If not, see <http://www.gnu.org/licenses/> // along with libAthena. If not, see <http://www.gnu.org/licenses/>
#include "Athena/SkywardSwordQuest.hpp" #include "Athena/SkywardSwordQuest.hpp"
#include "Athena/Checksums.hpp"
#include <sstream>
#include "utf8.h"
namespace Athena namespace Athena
{ {
namespace priv
{
static const atUint32 NAME_OFFSET = 0x08D4;
static const atUint32 RUPEE_COUNT_OFFSET = 0x0A5E;
static const atUint32 AMMO_COUNT_OFFSET = 0x0A60;
static const atUint32 MAX_HP_OFFSET = 0x5302;
static const atUint32 SPAWN_HP_OFFSET = 0x5304;
static const atUint32 CURRENT_HP_OFFSET = 0x5306;
static const atUint32 ROOM_ID_OFFSET = 0x5309;
static const atUint32 CURRENT_LOCATION_OFFSET = 0x531C;
static const atUint32 CURRENT_AREA_OFFSET = 0x533C;
static const atUint32 CURRENT_LOCATION_COPY_OFFSET = 0x535C;
static const atUint32 CHECKSUM_OFFSET = 0x53BC;
static const atUint32 ISNEW_OFFSET = 0x53AD;
static const atUint32 SKIP_CHECKSUM_OFFSET = 0x20;
}
union AmmoValues
{
struct
{
atUint32 arrows : 7;
atUint32 bombs : 7;
atUint32 : 9;
atUint32 seeds : 7;
atUint32 : 2;
};
atUint32 value;
};
SkywardSwordQuest::SkywardSwordQuest(atUint8 *data, atUint32 len) SkywardSwordQuest::SkywardSwordQuest(atUint8 *data, atUint32 len)
: ZQuestFile(ZQuestFile::SS, Endian::BigEndian, data, len), : ZQuestFile(ZQuestFile::SS, Endian::BigEndian, data, len),
m_skipData(nullptr), m_skipData(nullptr)
m_skipLength(0)
{ {
} }
void SkywardSwordQuest::setSkipData(const atUint8 *data, atUint32 len) void SkywardSwordQuest::setSkipData(const atUint8 *data)
{ {
if (m_skipData) if (m_skipData)
{ {
@ -34,7 +67,6 @@ void SkywardSwordQuest::setSkipData(const atUint8 *data, atUint32 len)
} }
m_skipData = (atUint8*)data; m_skipData = (atUint8*)data;
m_skipLength = len;
} }
atUint8 *SkywardSwordQuest::skipData() const atUint8 *SkywardSwordQuest::skipData() const
@ -42,9 +74,192 @@ atUint8 *SkywardSwordQuest::skipData() const
return m_skipData; return m_skipData;
} }
atUint32 SkywardSwordQuest::skipLength() const void SkywardSwordQuest::setPlayerName(const std::string& name)
{ {
return m_skipLength; if (name.length() > 8)
aDebug() << "WARNING: name cannot be greater than 8 characters, automatically truncating" << std::endl;
std::vector<atUint16> val;
utf8::utf8to16(name.begin(), name.end(), std::back_inserter(val));
for (atUint32 i = 0; i < 8; i++)
{
atUint16& c = *(atUint16*)(m_data + priv::NAME_OFFSET + (i * 2));
if (i >= val.size())
{
c = 0;
continue;
}
c = val[i];
utility::BigUint16(c);
}
}
std::string SkywardSwordQuest::playerName() const
{
std::vector<atUint16> val;
for (atUint32 i = 0; i < 8; i++)
{
atUint16 c = *(atUint16*)(m_data + priv::NAME_OFFSET + (i * 2));
if (c == 0)
break;
utility::BigUint16(c);
val.push_back(c);
}
std::string ret;
utf8::utf16to8(val.begin(), val.end(), std::back_inserter(ret));
return std::string(ret.c_str());
}
void SkywardSwordQuest::setRupeeCount(atUint16 value)
{
atUint16& tmp = *(atUint16*)(m_data + priv::RUPEE_COUNT_OFFSET);
tmp = value;
utility::BigUint16(tmp);
}
atUint16 SkywardSwordQuest::rupeeCount()
{
atUint16 ret = *(atUint16*)(m_data + priv::RUPEE_COUNT_OFFSET);
return utility::BigUint16(ret);
}
void SkywardSwordQuest::setAmmoCount(SkywardSwordQuest::AmmoType type, atUint32 count)
{
AmmoValues& values = *(AmmoValues*)(m_data + priv::AMMO_COUNT_OFFSET);
utility::BigUint32(values.value);
switch(type)
{
case Arrows:
values.arrows = count;
break;
case Bombs:
values.bombs = count;
break;
case Seeds:
values.seeds = count;
break;
}
utility::BigUint32(values.value);
}
atUint32 SkywardSwordQuest::ammoCount(AmmoType type)
{
AmmoValues values = *(AmmoValues*)(m_data + priv::AMMO_COUNT_OFFSET);
utility::BigUint32(values.value);
switch(type)
{
case Arrows: return values.arrows;
case Bombs: return values.bombs;
case Seeds: return values.seeds;
default: return 0;
}
}
void SkywardSwordQuest::setMaxHP(atUint16 val)
{
*(atUint16*)(m_data + priv::MAX_HP_OFFSET) = utility::BigUint16(val);
}
atUint16 SkywardSwordQuest::maxHP()
{
atUint16 ret = *(atUint16*)(m_data + priv::MAX_HP_OFFSET);
return utility::BigUint16(ret);
}
float SkywardSwordQuest::maxHearts()
{
return (maxHP() / 4.f);
}
void SkywardSwordQuest::setSpawnHP(atUint16 val)
{
*(atUint16*)(m_data + priv::SPAWN_HP_OFFSET) = utility::BigUint16(val);
}
atUint16 SkywardSwordQuest::spawnHP()
{
atUint16 ret = *(atUint16*)(m_data + priv::SPAWN_HP_OFFSET);
return utility::BigUint16(ret);
}
float SkywardSwordQuest::spawnHearts()
{
return (spawnHP() / 4.f);
}
void SkywardSwordQuest::setCurrentHP(atUint16 val)
{
*(atUint16*)(m_data + priv::CURRENT_HP_OFFSET) = utility::BigUint16(val);
}
atUint16 SkywardSwordQuest::currentHP()
{
atUint16 ret = *(atUint16*)(m_data + priv::CURRENT_HP_OFFSET);
return utility::BigUint16(ret);
}
float SkywardSwordQuest::currentHearts()
{
return (currentHP() / 4.f);
}
std::string SkywardSwordQuest::currentLocation()
{
return std::string((char*)m_data + priv::CURRENT_LOCATION_OFFSET);
}
std::string SkywardSwordQuest::currentArea()
{
return std::string((char*)m_data + priv::CURRENT_AREA_OFFSET);
}
std::string SkywardSwordQuest::currentLocationCopy()
{
return std::string((char*)m_data + priv::CURRENT_LOCATION_COPY_OFFSET);
}
atUint32 SkywardSwordQuest::slotChecksum()
{
atUint32 ret = *(atUint32*)(m_data + priv::CHECKSUM_OFFSET);
utility::BigUint32(ret);
return ret;
}
atUint32 SkywardSwordQuest::skipChecksum()
{
atUint32 ret = *(atUint32*)(m_skipData + priv::SKIP_CHECKSUM_OFFSET);
utility::BigUint32(ret);
return ret;
}
void SkywardSwordQuest::fixChecksums()
{
atUint32 checksum = Checksums::crc32(m_data, priv::CHECKSUM_OFFSET);
utility::BigUint32(checksum);
*(atUint32*)(m_data + priv::CHECKSUM_OFFSET) = checksum;
checksum = Checksums::crc32(m_skipData, priv::SKIP_CHECKSUM_OFFSET);
utility::BigUint32(checksum);
*(atUint32*)(m_skipData + priv::SKIP_CHECKSUM_OFFSET) = checksum;
}
void SkywardSwordQuest::setNew(bool isNew)
{
*(bool*)(m_data + priv::ISNEW_OFFSET) = isNew;
}
bool SkywardSwordQuest::isNew() const
{
return *(bool*)(m_data + priv::ISNEW_OFFSET);
} }
} // zelda } // zelda

View File

@ -374,5 +374,22 @@ atUint64 fileSize(FILE* f)
return size; return size;
} }
std::string& ltrim(std::string& s)
{
s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
return s;
}
std::string& rtrim(std::string& s)
{
s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
return s;
}
std::string& trim(std::string& s)
{
return ltrim(rtrim(s));
}
} // utility } // utility
} // Athena } // Athena

View File

@ -51,7 +51,7 @@ WiiSave::~WiiSave()
} }
void WiiSave::addFile(const std::string& filepath, WiiFile* file) void WiiSave::addFile( WiiFile* file)
{ {
m_root->addChild(file); m_root->addChild(file);
} }