mirror of https://github.com/libAthena/athena.git
* Start to fill in save related classes
* Fix silly bug in WiiSave * Fix typos in Utilitiy.*
This commit is contained in:
parent
fea9a45a5c
commit
be135d1caa
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 <rim(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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
#include "MCSlot.hpp"
|
||||||
|
|
||||||
|
namespace Athena
|
||||||
|
{
|
||||||
|
|
||||||
|
MCSlot::MCSlot(atUint8* data, atUint32 length)
|
||||||
|
: ZQuestFile(ZQuestFile::MC, Endian::LittleEndian, data, length)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
} // Athena
|
|
@ -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
|
|
@ -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++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue