Ejemplo n.º 1
0
class Write16(mrc.Block):
    value = mrc.UInt16_BE(0x00)

    @property
    def repr(self):
        return f'0x{self.value:04x}'
Ejemplo n.º 2
0
class ScriptChannelV4(mrc.Block):
    index = mrc.UInt16_BE(0x00)
Ejemplo n.º 3
0
class SordV4(mrc.Block):
    unk1 = mrc.Bytes(0x00, length=0xc)
    count = mrc.UInt32_BE(0x0c)
    unk2 = mrc.UInt16_BE(0x10)
    unk3 = mrc.UInt16_BE(0x12)
    index = mrc.UInt16_BE(0x14, count=mrc.Ref('count'))
Ejemplo n.º 4
0
    def import_data(self, buffer, parent=None):
        assert utils.is_bytes(buffer)
        pattern_count = mrc.UInt16_BE(0x0000).get_from_buffer(buffer)
        xor_mode = (pattern_count & 0x8000) != 0
        pattern_count &= 0x7fff

        index = 2
        lut = {}
        prev_pal_index = 0
        while index < len(buffer):
            test = buffer[index]
            if test == 0xff:
                break
            elif test & 0x80:
                code_raw = buffer[index + 2]
                bit_count = buffer[index + 1] & 0x0f
                code = ''.join([
                    '1' if (code_raw & (1 << i)) else '0'
                    for i in range(bit_count - 1, -1, -1)
                ])

                lut[code] = {
                    'pal_index': buffer[index] & 0x0f,
                    'copy_count': ((buffer[index + 1] & 0xf0) >> 4) + 1,
                }
                prev_pal_index = lut[code]['pal_index']
                index += 3
            else:
                code_raw = buffer[index + 1]
                bit_count = buffer[index] & 0x0f
                code = ''.join([
                    '1' if (code_raw & (1 << i)) else '0'
                    for i in range(bit_count - 1, -1, -1)
                ])

                lut[code] = {
                    'pal_index': prev_pal_index,
                    'copy_count': ((buffer[index] & 0xf0) >> 4) + 1,
                }
                index += 2

        bs = bits.BitStream(buffer[index + 1:], 0, bit_endian='big')

        state = {
            'output': bytearray(64 * pattern_count),
            'output_index': 0,
            'current_row': [],
            'prev_row': bytearray(8)
        }

        def push_pal(pal, state):
            state['current_row'].append(pal)
            if len(state['current_row']) == 8:
                output_index = state['output_index']
                for i in range(8):
                    state['output'][output_index + i] = state['current_row'][i]
                if xor_mode:
                    for i in range(8):
                        state['output'][output_index +
                                        i] ^= state['prev_row'][i]
                    prev_row = state['output'][output_index:output_index + 8]
                state['output_index'] += 8
                state['current_row'].clear()
            return

        max_key_size = max([len(x) for x in lut.keys()])
        while state['output_index'] < 64 * pattern_count:
            test = ''
            for i in range(max_key_size):
                test += '1' if bs.read(1) else '0'
                if test in lut or test == '111111':
                    break

            if test in lut:
                for i in range(lut[test]['copy_count']):
                    push_pal(lut[test]['pal_index'], state)
            elif test == '111111':
                copy_count = bs.read(3)
                pal_index = bs.read(4)
                for i in range(copy_count):
                    push_pal(pal_index, state)
            else:
                raise Exception('Invalid code found in data stream, aborting')

        return bytes(state['output'])
Ejemplo n.º 5
0
class OddRecord(mrc.Block):
    """Represents an alternative set of conditions for a level.
    
    Used in Lemmings to repeat the same level with a different difficulty.
    """

    #: Minimum Lemming release-rate.
    release_rate = mrc.UInt16_BE(0x0000, range=range(0, 251))
    #: Number of Lemmings released.
    num_released = mrc.UInt16_BE(0x0002, range=range(0, 115))
    #: Number of Lemmings required to be saved.
    num_to_save = mrc.UInt16_BE(0x0004, range=range(0, 115))
    #: Time limit for the level (minutes).
    time_limit_mins = mrc.UInt16_BE(0x0006, range=range(0, 256))
    #: Number of Climber skills.
    num_climbers = mrc.UInt16_BE(0x0008, range=range(0, 251))
    #: Number of Floater skills.
    num_floaters = mrc.UInt16_BE(0x000a, range=range(0, 251))
    #: Number of Bomber skills.
    num_bombers = mrc.UInt16_BE(0x000c, range=range(0, 251))
    #: Number of Blocker skills.
    num_blockers = mrc.UInt16_BE(0x000e, range=range(0, 251))
    #: Number of Builder skills.
    num_builders = mrc.UInt16_BE(0x0010, range=range(0, 251))
    #: Number of Basher skills.
    num_bashers = mrc.UInt16_BE(0x0012, range=range(0, 251))
    #: Number of Miner skills.
    num_miners = mrc.UInt16_BE(0x0014, range=range(0, 251))
    #: Number of Digger skills.
    num_diggers = mrc.UInt16_BE(0x0016, range=range(0, 251))

    #: Name of the level (ASCII string).
    name = mrc.Bytes(0x0018,
                     length=32,
                     default=b'                                ')

    @property
    def repr(self):
        return self.name.strip().decode('utf8')
Ejemplo n.º 6
0
class Level(mrc.Block):
    """Represents a single Lemmings level."""

    #: Minimum Lemming release-rate.
    release_rate = mrc.UInt16_BE(0x0000, range=range(0, 251))
    #: Number of Lemmings released.
    num_released = mrc.UInt16_BE(0x0002, range=range(0, 115))
    #: Number of Lemmings required to be saved.
    num_to_save = mrc.UInt16_BE(0x0004, range=range(0, 115))
    #: Time limit for the level (minutes).
    time_limit_mins = mrc.UInt16_BE(0x0006, range=range(0, 256))
    #: Number of Climber skills.
    num_climbers = mrc.UInt16_BE(0x0008, range=range(0, 251))
    #: Number of Floater skills.
    num_floaters = mrc.UInt16_BE(0x000a, range=range(0, 251))
    #: Number of Bomber skills.
    num_bombers = mrc.UInt16_BE(0x000c, range=range(0, 251))
    #: Number of Blocker skills.
    num_blockers = mrc.UInt16_BE(0x000e, range=range(0, 251))
    #: Number of Builder skills.
    num_builders = mrc.UInt16_BE(0x0010, range=range(0, 251))
    #: Number of Basher skills.
    num_bashers = mrc.UInt16_BE(0x0012, range=range(0, 251))
    #: Number of Miner skills.
    num_miners = mrc.UInt16_BE(0x0014, range=range(0, 251))
    #: Number of Digger skills.
    num_diggers = mrc.UInt16_BE(0x0016, range=range(0, 251))
    #: Raw value for the start x position of the camera.
    camera_x_raw = mrc.UInt16_BE(0x0018, range=range(0, 1265))

    #: Index denoting which graphical Style to use.
    style_index = mrc.UInt16_BE(0x001a)
    #: Index denoting which Special graphic to use (optional).
    custom_index = mrc.UInt16_BE(0x001c)

    #: List of Interactive object references (32 slots).
    interactives = mrc.BlockField(Interactive,
                                  0x0020,
                                  count=32,
                                  fill=b'\x00' * 8)
    #: List of Terrain object references (400 slots).
    terrains = mrc.BlockField(Terrain, 0x0120, count=400, fill=b'\xff' * 4)
    #: List of SteelArea object references (32 slots).
    steel_areas = mrc.BlockField(SteelArea, 0x0760, count=32, fill=b'\x00' * 4)
    #: Name of the level (ASCII string).
    name = mrc.Bytes(0x07e0,
                     length=32,
                     default=b'                                ')

    @property
    def camera_x(self):
        """Start x position of the camera."""
        return self.camera_x_raw - (self.camera_x_raw % 8)

    @property
    def repr(self):
        return self.name.strip().decode('utf8')
Ejemplo n.º 7
0
 class Test(mrc.Block):
     field1 = mrc.UInt16_BE(0x00)
     field2 = mrc.Int32_LE()
     field3 = mrc.Bits8(0x08, bits=0b00111100)
     field4 = mrc.Bits8(0x08, bits=0b11000011)
     field5 = mrc.Int8(enum=TestEnum)
Ejemplo n.º 8
0
class ChannelV4(mrc.Block):
    channel_size = mrc.UInt16_BE(0x00)
    channel_offset = mrc.UInt16_BE(0x02)
    data = mrc.Bytes(0x04, length=mrc.Ref('channel_size'))