// 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 ALTTPFileReader::ALTTPFileReader(Uint8* data, Uint64 length) : BinaryReader(data, length) { } ALTTPFileReader::ALTTPFileReader(const std::string& filename) : BinaryReader(filename) { } ALTTPFile* ALTTPFileReader::readFile() { std::vector quests; std::vector backup; for (Uint32 i = 0; i < 6; i++) { 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*)this->readBytes(sizeof(ALTTPInventory))); quest->setRupeeMax(this->readUInt16()); quest->setRupeeCurrent(this->readUInt16()); quest->setCompasses(readDungeonFlags()); quest->setBigKeys(readDungeonFlags()); quest->setDungeonMaps(readDungeonFlags()); quest->setWishingPond(this->readUInt16()); quest->setHealthMax(this->readByte()); quest->setHealth(this->readByte()); quest->setMagicPower(this->readByte()); quest->setKeys(this->readByte()); quest->setBombUpgrades(this->readByte()); quest->setArrowUpgrades(this->readByte()); quest->setHealthFiller(this->readByte()); quest->setMagicFiller(this->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(this->readByte()); quest->setArrowFiller(this->readByte()); quest->setArrows(this->readByte()); this->seek(1); ALTTPAbilities abilities; abilities.Nothing = this->readBit(); abilities.Swim = this->readBit(); abilities.Dash = this->readBit(); abilities.Pull = this->readBit(); abilities.Unknown1 = this->readBit(); abilities.Talk = this->readBit(); abilities.Read = this->readBit(); abilities.Unknown2 = this->readBit(); quest->setAbilityFlags(abilities); quest->setCrystals((ALTTPCrystals&)*this->readBytes(sizeof(ALTTPCrystals))); quest->setMagicUsage((ALTTPMagicUsage&)*this->readBytes(sizeof(ALTTPMagicUsage))); j = 0x10; while ((j--) > 0) { dungeonKeys.push_back(this->readByte()); } quest->setDungeonKeys(dungeonKeys); seek(0x039); quest->setProgressIndicator((ALTTPProgressIndicator)this->readByte()); quest->setProgressFlags1((ALTTPProgressFlags1&)*this->readBytes(sizeof(ALTTPProgressFlags1))); quest->setMapIcon((ALTTPMapIcon)this->readByte()); quest->setStartLocation((ALTTPStartLocation)this->readByte()); quest->setProgressFlags2((ALTTPProgressFlags2&)*this->readBytes(sizeof(ALTTPProgressFlags2))); quest->setLightDarkWorldIndicator((ALTTPLightDarkWorldIndicator&)*this->readBytes(1)); this->seek(1); quest->setTagAlong((ALTTPTagAlong)this->readByte()); j = 6; while((j--) > 0) { oldmanFlags.push_back(this->readByte()); } quest->setOldManFlags(oldmanFlags); quest->setBombFlag(this->readByte()); j = 5; while((j--) > 0) { unknown1.push_back(this->readByte()); } quest->setUnknown1(unknown1); j = 6; while((j--) > 0) { playerName.push_back(this->readUInt16()); } quest->setPlayerName(playerName); quest->setValid((this->readUInt16() == 0x55AA)); j = 0x0D; while((j--) > 0) { dungeonDeaths.push_back(this->readUInt16()); } quest->setDungeonDeathTotals(dungeonDeaths); quest->setUnknown2(this->readUInt16()); quest->setDeathSaveCount(this->readUInt16()); quest->setPostGameDeathCounter(this->readInt16()); this->seek(0xF7); quest->setChecksum(this->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 = readBit(); flags->Chest2 = readBit(); flags->Chest3 = readBit(); flags->Chest4 = readBit(); flags->Quadrant1 = readBit(); flags->Quadrant2 = readBit(); flags->Quadrant3 = readBit(); flags->Quadrant4 = readBit(); flags->Door1 = readBit(); flags->Door2 = readBit(); flags->Door3 = readBit(); flags->Door4 = readBit(); flags->BossBattleWon = readBit(); flags->Key = readBit(); flags->KeyOrChest = readBit(); flags->ChestOrTile = readBit(); return flags; } ALTTPOverworldEvent* ALTTPFileReader::readOverworldEvent() { ALTTPOverworldEvent* event = new ALTTPOverworldEvent; event->Unused1 = readBit(); event->HeartPiece= readBit(); event->Overlay= readBit(); event->Unused2= readBit(); event->Unused3= readBit(); event->Unused4= readBit(); event->Set= readBit(); event->Unused5= readBit(); return event; } ALTTPDungeonItemFlags ALTTPFileReader::readDungeonFlags() { ALTTPDungeonItemFlags flags; flags.Unused1 = readBit(); flags.GanonsTower = readBit(); flags.TurtleRock = readBit(); flags.GargoylesDomain = readBit(); flags.TowerOfHera = readBit(); flags.IcePalace = readBit(); flags.SkullWoods = readBit(); flags.MiseryMire = readBit(); flags.DarkPalace = readBit(); flags.SwampPalace = readBit(); flags.HyruleCastle2 = readBit(); flags.DesertPalace = readBit(); flags.EasternPalace = readBit(); flags.HyruleCastle = readBit(); flags.SewerPassage = readBit(); return flags; }