Source code for mrcrowbar.lib.platforms.clickteam

from mrcrowbar import models as mrc
from mrcrowbar.lib.images import base as img
from mrcrowbar.lib.audio import base as aud
from mrcrowbar import utils

# taken from KNPS.DLL at offset 0x13772 (1236:0372), len 0x400

KLIK_PALETTE_RAW =  '00000000800000000080000080800000000080008000800000808000c0c0c000'\
                    'c0dcc000a6caf000ffa70004d7870004b36b07048b4f07046737070443230704'\
                    '27002f043b003f044f004f04630057047300570483005b0497005704a7004f04'\
                    'b7004704cb003b04cf002f04d3001f04db001304df000704e3000004e7130004'\
                    'ef230004f3330004f7430004ff570004ff630004ff6f0004ff7f0004ff8b0004'\
                    'ff970004ffa30004ffaf0004ffbf0004ffcb0004ffd70004ffe30004ffef0004'\
                    'ffff0004efff0004dfff0004cfff0004bfff0004afff00049fff00048fff0004'\
                    '7fff00046fff00045fff00044fff00043fff00042fff00041fff00040fff0004'\
                    '00ff000400f3000400e7000400df000400d3000400c7000400bf000400b30004'\
                    '00a70004009b0004008f000400830004007b0004006f000400630004005b0004'\
                    '00530004005b070400670b0400731304007b1f040087270400933704009b4304'\
                    '00a7530400b3630400bb730400c7870400d39f0400dfb30400e7cb0400f3e304'\
                    '00ffff0400e7fb0400d3f70400bbf30400a7ef040093e704007fe304006fdf04'\
                    '005bdb04004bd7040037d3040027cf040017cb040007c7040000c3040f00bf04'\
                    '1b00bb043300b3044b00ab045f00a3046f009b047f0093048b00870483006b04'\
                    '7b0053048b0063049b007304ab008704bb009b04cb00b304db00cb04eb00e304'\
                    'ff00ff04ff00f304ff00e704ff00db04ff00cf04ff00c704ff00bb04ff00af04'\
                    'ff00a304ff009b04ff008f04ff008304ff007704ff006b04ff006304ff005704'\
                    'ff004b04ff003f04ff003704ff002b04ff001f04ff001304ff000704ff000004'\
                    'ffffff04efefef04dfdfdf04cfcfcf04bfbfbf04afafaf049f9f9f048f8f8f04'\
                    '7f7f7f046f6f6f045f5f5f044f4f4f043f3f3f042f2f2f041f1f1f040f0f0f04'\
                    '00000004fff3e704f7e3d304efd7bf04e7c7ab04dfbb9b04d7af8b04cfa37b04'\
                    'c7976b04bf8b5f04b77f4f04af774304a76b37049f632f04975723048f4f1b04'\
                    '8747130400000004fb000004ef000704e3000f04d7001704cf001b04c3002304'\
                    'b7002704ab002b04a3002f0497002f048b00330483003304770033046b003304'\
                    '5f002f0457002f040000bf04000097040000730400005b0400003f0400000004'\
                    'ff003b04ff1f6304ff438f04ff639f04ff87bf04ffa7cf04ffcbff0487471304'\
                    '733b0f0463330b04532b0b0443230704331b07041f0f00040f07000400000004'\
                    '87c3d30467abbf044b9baf042f879b041b738b040b63770400536704003f4f04'\
                    '002f3b04ff00ff04000000040000000400000004000000040000000400000004'\
                    '000000040000000400000004000000040000000400000004fffbf000a0a0a400'\
                    '80808000ff00000000ff0000ffff00000000ff00ff00ff0000ffff00ffffff00'

KLIK_PALETTE = img.from_palette_bytes( bytes.fromhex( KLIK_PALETTE_RAW ), stride=4, order=(0, 1, 2) )
KLIK_PALETTE[0] = img.Transparent()


# source: forum post by Jeremy Penner
# https://www.glorioustrainwrecks.com/node/294

[docs] class ImageRLE( mrc.Transform ):
[docs] def import_data( self, buffer, parent=None ): assert utils.is_bytes( buffer ) pointer = 0 result = bytearray() while pointer < len( buffer ): test = buffer[pointer] pointer += 1 if test & 0x80: result += buffer[pointer:pointer+(test & 0x7f)] pointer += (test & 0x7f) else: result += buffer[pointer:pointer+1]*test pointer += 1 return mrc.TransformResult( payload=bytes( result ), end_offset=pointer )
[docs] class ImageData( mrc.Block ): unk1 = mrc.Bytes( 0x00, length=6 ) size = mrc.UInt16_LE( 0x06 ) unk2 = mrc.UInt16_LE( 0x08 ) width_raw = mrc.UInt16_LE( 0x0a ) height = mrc.UInt16_LE( 0x0c ) unk3 = mrc.UInt16_LE( 0x0e, count=5 ) data = mrc.Bytes( 0x18, length=mrc.Ref( 'size' ), transform=ImageRLE() ) @property def width( self ): return self.width_raw - (self.width_raw % 2) + (2 if (self.width_raw % 2) else 0) def __init__( self, *args, **kwargs ): super().__init__( *args, **kwargs ) self.image = img.IndexedImage( self, mrc.Ref( 'data' ), mrc.Ref( 'width' ), mrc.Ref( 'height' ), palette=KLIK_PALETTE )
[docs] class ImageEntry( mrc.Block ): offset = mrc.UInt32_LE( 0x00 ) size = mrc.UInt32_LE( 0x04 ) image = mrc.StoreRef( ImageData, mrc.Ref( '_parent.images' ), mrc.Ref( 'offset' ), mrc.Ref( 'size' ) )
[docs] class IMGFile( mrc.Block ): count = mrc.UInt32_LE( 0x00 ) entries = mrc.BlockField( ImageEntry, 0x04, count=mrc.Ref( 'count' ) ) images_raw = mrc.Bytes( mrc.EndOffset( 'entries' ) ) def __init__( self, *args, **kwargs ): self.images = mrc.Store( parent=self, source=mrc.Ref( 'images_raw' ), base_offset=mrc.EndOffset( 'entries', neg=True ) ) super().__init__( *args, **kwargs )
[docs] class SoundData( mrc.Block ): unk1 = mrc.UInt32_LE( 0x00 ) unk2 = mrc.UInt16_LE( 0x04 ) unk3 = mrc.UInt32_LE( 0x06 ) unk4 = mrc.Bytes( 0x0a, length=0x12 ) unk5 = mrc.UInt32_LE( 0x1c ) unk6 = mrc.UInt16_LE( 0x20 ) unk7 = mrc.UInt16_LE( 0x22 ) sample_rate = mrc.UInt32_LE( 0x24 ) playback_rate = mrc.UInt32_LE( 0x28 ) channels = mrc.UInt16_LE( 0x2c ) sample_bits = mrc.UInt16_LE( 0x2e ) data = mrc.Bytes( 0x30 ) @property def sample_signedness( self ): return 'unsigned' if self.sample_bits == 8 else 'signed' @property def sample_width( self ): return self.sample_bits // 8 def __init__( self, *argc, **argv ): self.audio = aud.Wave( self, mrc.Ref( 'data' ), mrc.Ref( 'channels' ), mrc.Ref( 'sample_rate' ), int, mrc.Ref( 'sample_width' ), mrc.Ref( 'sample_signedness' ), 'big' ) super().__init__( *argc, **argv )
[docs] class SoundEntry( mrc.Block ): offset = mrc.UInt32_LE( 0x00 ) size = mrc.UInt32_LE( 0x04 ) sound = mrc.StoreRef( SoundData, mrc.Ref( '_parent.sounds' ), mrc.Ref( 'offset' ), mrc.Ref( 'size' ) )
[docs] class SNDFile( mrc.Block ): count = mrc.UInt32_LE( 0x00 ) entries = mrc.BlockField( SoundEntry, 0x04, count=mrc.Ref( 'count' ) ) sound_raw = mrc.Bytes( mrc.EndOffset( 'entries' ) ) def __init__( self, *args, **kwargs ): self.sounds = mrc.Store( parent=self, source=mrc.Ref( 'sound_raw' ), base_offset=mrc.EndOffset( 'entries', neg=True ) ) super().__init__( *args, **kwargs )
[docs] class MusicData( mrc.Block ): unk1 = mrc.Bytes( 0x00, length=0x20 ) midi = mrc.Bytes( 0x20 )
[docs] class MusicEntry( mrc.Block ): offset = mrc.UInt32_LE( 0x00 ) size = mrc.UInt32_LE( 0x04 ) music = mrc.StoreRef( MusicData, mrc.Ref( '_parent.tracks' ), mrc.Ref( 'offset' ), mrc.Ref( 'size' ) )
[docs] class MUSFile( mrc.Block ): count = mrc.UInt32_LE( 0x00 ) entries = mrc.BlockField( MusicEntry, 0x04, count=mrc.Ref( 'count' ) ) music_raw = mrc.Bytes( mrc.EndOffset( 'entries' ) ) def __init__( self, *args, **kwargs ): self.tracks = mrc.Store( parent=self, source=mrc.Ref( 'music_raw' ), base_offset=mrc.EndOffset( 'entries', neg=True ) ) super().__init__( *args, **kwargs )