///////////////////////////////////////////////////////////
    // 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;
    }
Esempio n. 2
0
    ///////////////////////////////////////////////////////////
    // 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;
    }