/////////////////////////////////////////////////////////// // Function type: I/O // Contributors: Pokedude // Last edit by: Pokedude // Date of edit: 6/15/2016 // /////////////////////////////////////////////////////////// bool MapBank::read(const qboy::Rom &rom, UInt32 offset, UInt32 next) { if (!rom.seek(offset)) AME_THROW(BNK_ERROR_OFFSET, rom.redirected()); // User can choose whether to retrieve the map-count // on a fast or accurate way (horiz. slider) // Level 0: Checks for next bank and ptr validity + // Level 1: Checks for ptr validity within the map header + // Level 2: Checks for ptr validity within the layout header + // Level 3: Checks for ptr validity within the events + // Level 4: Checks certain properties in tilesets and events int accLevel = SETTINGS(MapAccuracyLevel); // Retrieves the map count through various checks while (true) { if (!rom.seek(offset + (++m_Count) * 4)) AME_THROW(BNK_ERROR_WHILE, offset + m_Count * 4); // ============= LEVEL 0 ============= // Checks if current offset is start of bank table if (rom.offset() == CONFIG(MapBanks)) break; // Checks if current offset is next bank if (rom.offset() == next) break; // Checks if map pointer is valid unsigned map = rom.readPointer(); if (!rom.seek(map)) break; // ============= LEVEL 1 ============= if (accLevel == 0) continue; // Checks if the layout header and event pointers are valid unsigned footer = rom.readPointer(); if (!rom.checkOffset(footer)) break; unsigned events = rom.readPointer(); if (!rom.checkOffset(events)) break; // ============= LEVEL 2 ============= if (accLevel == 1) continue; // Checks if the border, blocks, primary and secondary pointers are valid rom.seek(footer); rom.readWord(); rom.readWord(); if (!rom.checkOffset(rom.readPointer())) break; if (!rom.checkOffset(rom.readPointer())) break; unsigned primary = rom.readPointer(); if (!rom.checkOffset(primary)) break; unsigned secondary = rom.readPointer(); if (!rom.checkOffset(secondary)) break; // ============= LEVEL 3 ============= if (accLevel == 2) continue; // Checks if the npc, warp, trigger and sign pointers are valid // Events are not necessary for a map if (events) { rom.seek(events); rom.readWord(); if (!rom.checkOffset(rom.readPointer())) break; if (!rom.checkOffset(rom.readPointer())) break; if (!rom.checkOffset(rom.readPointer())) break; if (!rom.checkOffset(rom.readPointer())) break; } // ============= LEVEL 4 ============= if (accLevel == 3) continue; // Checks the first two tileset settings rom.seek(primary); if (rom.readByte() >= 2) // compression can only be 0/1 break; if (rom.readByte() != 0) // must be primary tileset! break; rom.seek(secondary); if (rom.readByte() >= 2) // compression can only be 0/1 break; if (rom.readByte() != 1) // must be secondary tileset! break; } // Now attempts to read all the maps for (int i = 0; i < m_Count; i++) { rom.seek(offset + i * 4); // Retrieves the pointer to the map Map *map = new Map; UInt32 mapOff = rom.readPointerRef(); // Attempts to read the map if (!map->read(rom, mapOff)) { delete map; return false; } m_Maps.push_back(map); } // Loading successful m_Offset = offset; return true; }
/////////////////////////////////////////////////////////// // 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 // Contributors: Pokedude, Diegoisawesome // Last edit by: Diegoisawesome // Date of edit: 7/3/2016 // /////////////////////////////////////////////////////////// bool MapLayoutTable::read(const qboy::Rom &rom, UInt32 offset) { if (!rom.seek(offset)) AME_THROW(LAY_ERROR_OFFSET, rom.redirected()); // Checks for ptr validity within the layout header and // certain properties in tilesets // Retrieves the map count through various checks while (true) { if (!rom.seek(offset + (++m_Count) * 4)) AME_THROW(LAY_ERROR_WHILE, offset + m_Count * 4); unsigned layout = rom.readPointer(); if (layout == 0) continue; if (!rom.seek(layout)) break; // Checks if the border, blocks, primary and secondary pointers are valid rom.readWord(); rom.readWord(); if (!rom.checkOffset(rom.readPointer())) break; if (!rom.checkOffset(rom.readPointer())) break; unsigned primary = rom.readPointer(); if (!rom.checkOffset(primary)) break; unsigned secondary = rom.readPointer(); if (!rom.checkOffset(secondary)) break; /* // Checks the first two tileset settings rom.seek(primary); if (rom.readByte() >= 2) // compression can only be 0/1 break; if (rom.readByte() != 0) // must be primary tileset! break; rom.seek(secondary); if (rom.readByte() >= 2) // compression can only be 0/1 break; if (rom.readByte() != 1) // must be secondary tileset! break;*/ } // Now attempts to read all the maps for (int i = 0; i < m_Count; i++) { rom.seek(offset + i * 4); // Retrieves the pointer to the map MapHeader *mapHeader = new MapHeader; UInt32 mapOff = rom.readPointerRef(); // Attempts to read the map layout if (mapOff != 0 && !mapHeader->read(rom, mapOff)) { delete mapHeader; return false; } m_MapHeaders.push_back(mapHeader); } // Loading successful m_Offset = offset; return true; }