// This file is part of libZelda.
//
// libZelda is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// libZelda is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with libZelda. If not, see
#include "ALTTPFileReader.hpp"
#include "ALTTPFile.hpp"
#include "ALTTPQuest.hpp"
#include
namespace zelda
{
namespace io
{
ALTTPFileReader::ALTTPFileReader(Uint8* data, Uint64 length)
: base(data, length)
{
}
ALTTPFileReader::ALTTPFileReader(const std::string& filename)
: base(filename)
{
}
ALTTPFile* ALTTPFileReader::readFile()
{
std::vector quests;
std::vector backup;
for (Uint32 i = 0; i < 6; i++)
{
// Temporary values to use for each save
ALTTPQuest* quest = new ALTTPQuest();
std::vector roomFlags;
std::vector owEvents;
std::vector dungeonKeys;
std::vector oldmanFlags;
std::vector unknown1;
std::vector playerName;
std::vector dungeonDeaths;
int j = 0x140;
while ((j--) > 0)
{
roomFlags.push_back(readRoomFlags());
}
quest->setRoomFlags(roomFlags);
j = 0x0C0;
while ((j--) > 0)
owEvents.push_back(readOverworldEvent());
quest->setOverworldEvents(owEvents);
quest->setInventory((ALTTPInventory*)base::readBytes(sizeof(ALTTPInventory)));
quest->setRupeeMax(base::readUInt16());
quest->setRupeeCurrent(base::readUInt16());
quest->setCompasses(readDungeonFlags());
quest->setBigKeys(readDungeonFlags());
quest->setDungeonMaps(readDungeonFlags());
quest->setWishingPond(base::readUInt16());
quest->setHealthMax(base::readByte());
quest->setHealth(base::readByte());
quest->setMagicPower(base::readByte());
quest->setKeys(base::readByte());
quest->setBombUpgrades(base::readByte());
quest->setArrowUpgrades(base::readByte());
quest->setHealthFiller(base::readByte());
quest->setMagicFiller(base::readByte());
ALTTPPendants pendants;
pendants.Courage = readBit();
pendants.Wisdom = readBit();
pendants.Power = readBit();
pendants.Unused1 = false;
pendants.Unused2 = false;
pendants.Unused3 = false;
pendants.Unused4 = false;
pendants.Unused5 = false;
quest->setPendants(pendants);
quest->setBombFiller(base::readByte());
quest->setArrowFiller(base::readByte());
quest->setArrows(base::readByte());
base::seek(1);
ALTTPAbilities abilities;
abilities.Nothing = base::readBit();
abilities.Swim = base::readBit();
abilities.Dash = base::readBit();
abilities.Pull = base::readBit();
abilities.Unknown1 = base::readBit();
abilities.Talk = base::readBit();
abilities.Read = base::readBit();
abilities.Unknown2 = base::readBit();
quest->setAbilityFlags(abilities);
quest->setCrystals((ALTTPCrystals&)*base::readBytes(sizeof(ALTTPCrystals)));
quest->setMagicUsage((ALTTPMagicUsage&)*base::readBytes(sizeof(ALTTPMagicUsage)));
j = 0x10;
while ((j--) > 0)
{
dungeonKeys.push_back(base::readByte());
}
quest->setDungeonKeys(dungeonKeys);
base::seek(0x039);
quest->setProgressIndicator((ALTTPProgressIndicator)base::readByte());
quest->setProgressFlags1((ALTTPProgressFlags1&)*base::readBytes(sizeof(ALTTPProgressFlags1)));
quest->setMapIcon((ALTTPMapIcon)base::readByte());
quest->setStartLocation((ALTTPStartLocation)base::readByte());
quest->setProgressFlags2((ALTTPProgressFlags2&)*base::readBytes(sizeof(ALTTPProgressFlags2)));
quest->setLightDarkWorldIndicator((ALTTPLightDarkWorldIndicator&)*base::readBytes(1));
base::seek(1);
quest->setTagAlong((ALTTPTagAlong)base::readByte());
j = 6;
while((j--) > 0)
{
oldmanFlags.push_back(base::readByte());
}
quest->setOldManFlags(oldmanFlags);
quest->setBombFlag(base::readByte());
j = 5;
while((j--) > 0)
{
unknown1.push_back(base::readByte());
}
quest->setUnknown1(unknown1);
j = 6;
while((j--) > 0)
{
playerName.push_back(base::readUInt16());
}
quest->setPlayerName(playerName);
quest->setValid((base::readUInt16() == 0x55AA));
j = 0x0D;
while((j--) > 0)
{
dungeonDeaths.push_back(base::readUInt16());
}
quest->setDungeonDeathTotals(dungeonDeaths);
quest->setUnknown2(base::readUInt16());
quest->setDeathSaveCount(base::readUInt16());
quest->setPostGameDeathCounter(base::readInt16());
base::seek(0xF7);
quest->setChecksum(base::readUInt16());
if (i < 3)
quests.push_back(quest);
else
backup.push_back(quest);
}
return new ALTTPFile(quests, backup);
}
ALTTPRoomFlags* ALTTPFileReader::readRoomFlags()
{
ALTTPRoomFlags* flags = new ALTTPRoomFlags;
flags->Chest1 = base::readBit();
flags->Chest2 = base::readBit();
flags->Chest3 = base::readBit();
flags->Chest4 = base::readBit();
flags->Quadrant1 = base::readBit();
flags->Quadrant2 = base::readBit();
flags->Quadrant3 = base::readBit();
flags->Quadrant4 = base::readBit();
flags->Door1 = base::readBit();
flags->Door2 = base::readBit();
flags->Door3 = base::readBit();
flags->Door4 = base::readBit();
flags->BossBattleWon = base::readBit();
flags->Key = base::readBit();
flags->KeyOrChest = base::readBit();
flags->ChestOrTile = base::readBit();
return flags;
}
ALTTPOverworldEvent* ALTTPFileReader::readOverworldEvent()
{
ALTTPOverworldEvent* event = new ALTTPOverworldEvent;
event->Unused1 = base::readBit();
event->HeartPiece = base::readBit();
event->Overlay = base::readBit();
event->Unused2 = base::readBit();
event->Unused3 = base::readBit();
event->Unused4 = base::readBit();
event->Set = base::readBit();
event->Unused5 = base::readBit();
return event;
}
ALTTPDungeonItemFlags ALTTPFileReader::readDungeonFlags()
{
ALTTPDungeonItemFlags flags;
flags.Unused1 = base::readBit();
flags.GanonsTower = base::readBit();
flags.TurtleRock = base::readBit();
flags.GargoylesDomain = base::readBit();
flags.TowerOfHera = base::readBit();
flags.IcePalace = base::readBit();
flags.SkullWoods = base::readBit();
flags.MiseryMire = base::readBit();
flags.DarkPalace = base::readBit();
flags.SwampPalace = base::readBit();
flags.HyruleCastle2 = base::readBit();
flags.DesertPalace = base::readBit();
flags.EasternPalace = base::readBit();
flags.HyruleCastle = base::readBit();
flags.SewerPassage = base::readBit();
return flags;
}
} // io
} // zelda