/////////////////////////////////////////////////////////// // Member functions // /////////////////////////////////////////////////////////// const QString String::read(const qboy::Rom &rom, UInt32 offset) { // Firstly, determines whether the given rom is valid Q_ASSERT(rom.info().isLoaded() && rom.info().isValid()); // Declares needed variables for the decoding process QList<UInt8> encoded; QString decoded; UInt8 readByte; // Declares the different dynamic tables (some are the same across all roms) QMap<UInt32, QString> *mapBuffers = NULL; QMap<UInt32, QString> *mapFunctions = NULL; // Determines the rom version and depending on that, loads the tables if (CONFIG(RomType) == RT_FRLG) { mapBuffers = &BufferSequencesFRLG; mapFunctions = &FunctionSequencesFRLG; } else if (CONFIG(RomType) == RT_RS) { mapBuffers = &BufferSequencesRSE; mapFunctions = &FunctionSequencesRS; } else { mapBuffers = &BufferSequencesRSE; mapFunctions = &FunctionSequencesE; } // Reads the whole Pokémon string, terminated by 0xFF if (!rom.seek(offset)) Q_ASSERT(false); while ((readByte = rom.readByte()) != 0xFF) encoded.push_back(readByte); // Iterates through every encoded character and interprets it int length = encoded.size(); for (int i = 0; i < length;) { // Fetches the char at the current position UInt8 currentChar = encoded.at(i++); if (currentChar == 0xF8 || currentChar == 0xF9) { // Character might be a symbol UInt8 arg1 = encoded[i++]; UInt32 search = ((currentChar << 8) | arg1); // Searches for the sequence in the symbol-map auto searchResult = SymbolSequences.find(search); if (searchResult != SymbolSequences.end()) decoded.push_back(searchResult.value()); else decoded.push_back(convertRaw(search)); } else if (currentChar == 0xFD) { // Character might be a buffer UInt8 arg1 = encoded.at(i++); UInt32 search = ((currentChar << 8) | arg1); // Searches for the sequence in the dynamic buffer-map auto searchResult = mapBuffers->find(search); if (searchResult != mapBuffers->end()) decoded.push_back(searchResult.value()); else decoded.push_back(convertRaw(search)); } else if (currentChar == 0xFC) { // Character might be an escape sequence UInt8 arg1 = encoded.at(i++); UInt32 search = 0; if (arg1 >= 1 && arg1 <= 6) { // Might be a multi-byte function UInt8 arg2 = encoded[i++]; search = ((currentChar << 16) | (arg1 << 8) | arg2); } else { // Might be a single-byte function search = ((currentChar << 8) | arg1); } // Searches for the sequence in the dynamic escape-map auto searchResult = mapFunctions->find(search); if (searchResult != mapFunctions->end()) decoded.push_back(searchResult.value()); else decoded.push_back(convertRaw(search)); } else { // Is a single character for sure (exception-safe!) decoded.push_back(SingleSequences.value(currentChar)); } } // Finished return decoded; }
/////////////////////////////////////////////////////////// // Function type: I/O // Contributors: Pokedude // Last edit by: Pokedude // Date of edit: 6/11/2016 // /////////////////////////////////////////////////////////// bool MapHeader::read(const qboy::Rom &rom, UInt32 offset) { if (!rom.seek(offset)) AME_THROW(HDR_ERROR_OFFSET, rom.redirected()); // Reads the map's dimensions m_Width = rom.readWord(); m_Height = rom.readWord(); // Reads all the pointers within the structure m_PtrBorder = rom.readPointerRef(); m_PtrBlocks = rom.readPointer(); m_PtrPrimary = rom.readPointerRef(); m_PtrSecondary = rom.readPointerRef(); // Determines whether these pointers are valid if (!rom.checkOffset(m_PtrBorder)) AME_THROW(HDR_ERROR_BORDER, offset + 8); if (!rom.checkOffset(m_PtrBlocks)) AME_THROW(HDR_ERROR_BLOCKS, offset + 12); if (!rom.checkOffset(m_PtrPrimary)) AME_THROW(HDR_ERROR_PRIMARY, offset + 16); if (!rom.checkOffset(m_PtrSecondary)) AME_THROW(HDR_ERROR_SECONDARY, offset + 20); // Retrieves the border (different between games!) if (rom.info().isFRLG()) { QSize borderSize(rom.readByte(), rom.readByte()); m_Border.read(rom, m_PtrBorder, borderSize); } else { m_Border.read(rom, m_PtrBorder, QSize(2, 2)); } // Retrieves the map block data rom.seek(m_PtrBlocks); for (unsigned i = 0; i < m_Width * m_Height; i++) { MapBlock *block = new MapBlock; UInt16 data = rom.readHWord(); block->block = (data & 0x3FF); block->permission = (data >> 0xA); m_Blocks.push_back(block); } // Loads the tilesets, if necessary if ((m_Primary = TilesetManager::get(m_PtrPrimary)) == NULL) { m_Primary = new Tileset; m_Primary->read(rom, m_PtrPrimary); TilesetManager::add(m_Primary); } if ((m_Secondary = TilesetManager::get(m_PtrSecondary)) == NULL) { m_Secondary = new Tileset; m_Secondary->read(rom, m_PtrSecondary); TilesetManager::add(m_Secondary); } // Loading successful return true; }
/////////////////////////////////////////////////////////// // Function type: I/O // Contributers: Pokedude // Last edit by: Pokedude // Date of edit: 6/5/2016 // /////////////////////////////////////////////////////////// bool Tileset::read(const qboy::Rom &rom, UInt32 offset) { if (!rom.seek(offset)) AME_THROW(SET_ERROR_OFFSET, rom.redirected()); // Reads the first two properties for the following determination m_IsCompressed = rom.readByte(); m_IsPrimary = rom.readByte(); rom.readHWord(); // padding // Determines all differences between FRLG and RSE int countPal; int countBlock; int palAdjustment; int uncompSize; if (rom.info().isFRLG()) { if (!m_IsPrimary) // = 0 in the games -.- { countPal = 7; countBlock = 640; palAdjustment = 0; uncompSize = 40960; } else { countPal = 6; countBlock = 384; palAdjustment = 224; uncompSize = 24576; } } else { if (!m_IsPrimary) // = 0 in the games -.- { countPal = 6; countBlock = 512; palAdjustment = 0; uncompSize = 32768; } else { countPal = 7; countBlock = 512; palAdjustment = 192; uncompSize = 32768; } } // Reads all pointers within the tileset structure m_PtrImage = rom.readPointer(); m_PtrPalette = rom.readPointer(); m_PtrBlocks = rom.readPointer(); if (rom.info().isFRLG()) // pointers reversed { m_PtrAnimations = rom.readPointer(); m_PtrBehaviour = rom.readPointer(); } else { m_PtrBehaviour = rom.readPointer(); m_PtrAnimations = rom.readPointer(); } // Determines whether all read pointers are valid if (!rom.checkOffset(m_PtrImage)) AME_THROW(SET_ERROR_IMAGE, offset + 4); if (!rom.checkOffset(m_PtrPalette)) AME_THROW(SET_ERROR_PALETTE, offset + 8); if (!rom.checkOffset(m_PtrBlocks)) AME_THROW(SET_ERROR_BLOCKS, offset + 12); if (!rom.checkOffset(m_PtrAnimations)) AME_THROW(SET_ERROR_ANIM, offset + 16); if (!rom.checkOffset(m_PtrBehaviour)) AME_THROW(SET_ERROR_PROP, offset + 20); // Attempts to load the image if (m_IsCompressed) { if (!m_Image->readCompressed(rom, m_PtrImage, 128, true)) AME_THROW(SET_ERROR_IMGDATA, m_PtrImage); } else { if (!m_Image->readUncompressed(rom, m_PtrImage, uncompSize, 128, true)) AME_THROW(SET_ERROR_IMGDATA, m_PtrImage); } // Attempts to load the palettes for (int i = 0; i < countPal; i++) { qboy::Palette *pal = new qboy::Palette; pal->readUncompressed(rom, m_PtrPalette + palAdjustment + i * 32, 16); m_Pals.push_back(pal); } // Attempts to load the blocks rom.seek(m_PtrBlocks); for (int i = 0; i < countBlock; i++) { Block *block = new Block; m_Blocks.push_back(block); // Each block has 2 layers á 4 tiles for (int j = 0; j < 8; j++) { Tile tile; UInt16 data = rom.readHWord(); // Extracts information from the hword tile.tile = (data & 0x3FF); tile.palette = ((data & 0xF800) >> 0xC); tile.flipX = ((data & 0x400) == 0x400); tile.flipY = ((data & 0x800) == 0x800); block->tiles[j] = tile; } } // Attempts to load the block properties m_Properties->read(rom, m_PtrBehaviour, countBlock); // Loading successful m_Offset = offset; return true; }