class Transition(DataLoader): module = None name = None id = None transitionId = None duration = None # in ms flags = None color = None parameterData = None def initialize(self): self.flags = BitDict('Color') def read(self, reader): self.module = reader.read(reader.readInt()) self.name = reader.read(reader.readInt()) self.id = reader.read(4) self.transitionId = reader.read(4) self.duration = reader.readInt() self.flags.setFlags(reader.readInt()) self.color = reader.readColor() self.parameterData = reader.read(reader.readInt()) def write(self, reader): reader.writeInt(len(self.module)) reader.write(self.module) reader.writeInt(len(self.name)) reader.write(self.name) reader.write(self.id) reader.write(self.transitionId) reader.writeInt(self.duration) reader.writeInt(self.flags.getFlags()) reader.writeColor(self.color) reader.writeInt(len(self.parameterData)) reader.write(self.parameterData)
class Transition(DataLoader): module = None name = None duration = None # in ms flags = None color = None moduleFile = None parameterData = None def __init__(self, reader: ByteIO): self.reader = reader self.flags = BitDict('Color') currentPosition = self.reader.tell() self.module = self.reader.read(4) self.name = self.reader.read(4) self.duration = self.reader.read_int32() self.flags.setFlags(self.reader.read_uint32()) self.color = [self.reader.read_uint8() for _ in range(4)] nameOffset = self.reader.read_int32() parameterOffset = self.reader.read_int32() parameterSize = self.reader.read_int32() self.reader.seek(currentPosition + nameOffset) self.moduleFile = self.reader.read_ascii_string() self.reader.seek(currentPosition + parameterOffset) self.parameterData = self.reader.read(parameterSize) def isStandard(self): return self.name == 'STDT'
class ExtendedHeader(DataLoader): def __init__(self, reader): self.reader = reader self.flags = BitDict( 'KeepScreenRatio', 'FrameTransition', # (HWA only) frame has a transition 'ResampleStretch', # (HWA only) resample while resizing 'GlobalRefresh' # (Mobile) force global refresh ) self.buildType = None self.buildFlags = None self.screenRatioTolerance = None self.screenAngle = None def read(self): self.flags.setFlags(self.reader.read_int32()) self.buildType = self.reader.read_uint32() self.buildFlags = self.reader.read_uint32() self.screenRatioTolerance = self.reader.read_int16() self.screenAngle = self.reader.read_int16() self.reader.read_int32() if self.buildType >= 0x10000000: self.update_settings(compat=True) def print(self): print(f'Flag: {self.flags}') print(f'Build type: {self.buildType}') print(f'Build flags: {self.buildFlags}') print(f'Screen ratio tolerance: {self.screenRatioTolerance}') print(f'Screen Angle: {self.screenAngle}')
class MusicFile(DataLoader): def __init__(self, reader: ByteIO): self.reader = reader self.handle = None self.name = None self.checksum = None self.references = None self.flags = BitDict( 'Wave', 'MIDI', None, None, 'LoadOnCall', 'PlayFromDisk', 'Loaded' ) self.data = None self.ext = '.mp3' def read(self): reader = self.reader debug = self.settings.get('debug', False) compressed = not debug and self.settings.get('compressed', True) self.handle = reader.read_int32() if compressed: reader = reader.auto_decompress(True) self.checksum = reader.read_uint32() self.references = reader.read_uint32() size = reader.read_uint32() self.flags.setFlags(reader.read_uint32()) reserved = reader.read_int32() name_length = reader.read_int32() self.name = reader.read_wide_string(name_length) self.data = reader.read_bytes(size - name_length) if self.flags['Wave']: self.ext = '.wav' elif self.flags['MIDI']: self.ext = '.midi' if self.settings.get('DUMPMUSIC', False) or self.settings.get('DUMPEVERYTHING', False): self.dump() def dump(self): if self.settings.get('VERBOSE', False): print(f'Saving "{self.name}{self.ext}"') with open(os.path.join(self.settings['dump_path'], 'MusicBank', f'{self.name}{self.ext}'), 'wb') as fp: fp.write(self.data) return self
class Layer(DataLoader): def __init__(self, reader: ByteIO): self.reader = reader self.name = '' self.flags = BitDict( 'XCoefficient', 'YCoefficient', 'DoNotSaveBackground', None, # Wrap (Obsolete) 'Visible', # visible 'WrapHorizontally', 'WrapVertically', None, None, None, None, None, None, None, None, None, 'Redraw', 'ToHide', 'ToShow' ) self.x_coefficient = 0 self.y_coefficient = 0 self.number_of_backgrounds = 0 self.background_index = 0 def read(self): reader = self.reader value = reader.read_uint32() self.flags.setFlags(value) self.x_coefficient = reader.read_float() self.y_coefficient = reader.read_float() self.number_of_backgrounds = reader.read_int32() self.background_index = reader.read_int32() self.name = reader.read_ascii_string() def write(self, reader: ByteIO): reader.write_uint32(self.flags.getFlags()) reader.write_float(self.x_coefficient) reader.write_float(self.y_coefficient) reader.write_int32(self.number_of_backgrounds) reader.write_int32(self.background_index) reader.write_ascii_string(self.name) def get_backgrounds(self, objectInstances): return objectInstances.items[ self.background_index:self.background_index + self.number_of_backgrounds] def get_instances(self, objectInstances): return self.parent.getObjectInstances(self, objectInstances)
class FrameHeader(DataLoader): def __init__(self, reader: ByteIO): self.reader = reader self.width = 0 self.height = 0 self.flags = BitDict( 'DisplayName', 'GrabDesktop', 'KeepDisplay', 'FadeIn', 'FadeOut', 'TotalCollisionMask', 'Password', 'ResizeAtStart', 'DoNotCenter', 'ForceLoadOnCall', 'NoSurface', 'Reserved_1', 'Reserved_2', 'RecordDemo', None, 'TimedMovements' ) self.background = None def read(self): reader = self.reader self.width = reader.read_int32() self.height = reader.read_int32() self.background = reader.read_fmt('BBBB') self.flags.setFlags(reader.read_uint32()) def write(self, reader: ByteIO): reader.write_int32(self.width) reader.write_int32(self.height) reader.write_fmt('BBBB', self.background) reader.write_uint32(self.flags.getFlags())
class Frame(DataLoader): handle = None name = None size = None background = None maxObjects = None password = None palette = None fadeIn = None fadeOut = None def initialize(self): self.palette = [] self.flags = BitDict('GrabDesktop', 'KeepDisplay', 'BackgroundCollisions', 'DisplayFrameTitle', 'ResizeToScreen', 'ForceLoadOnCall', 'NoDisplaySurface', 'ScreenSaverSetup', 'TimerBasedMovements', 'MochiAds', 'NoGlobalEvents') def read(self, reader): self.handle = reader.readInt() self.name = reader.read(reader.readInt()) self.size = (reader.readInt(), reader.readInt()) self.background = reader.readColor() self.flags.setFlags(reader.readInt(True)) self.maxObjects = reader.readInt() self.password = reader.read(reader.readInt()) checkDefault(reader, reader.readInt(), 0) self.lastViewedX = reader.readInt() self.lastViewedY = reader.readInt() self.palette = [reader.readColor() for _ in xrange(reader.readInt())] self.stampHandle = reader.readInt() self.activeLayer = reader.readInt() self.layers = [ self.new(Layer, reader) for _ in xrange(reader.readInt()) ] if reader.readByte() != 0: self.fadeIn = self.new(Transition, reader) if reader.readByte() != 0: self.fadeOut = self.new(Transition, reader) self.items = items = [ self.new(FrameItem, reader) for _ in xrange(reader.readInt()) ] self.folders = [ self.new(ItemFolder, reader) for _ in xrange(reader.readInt(True)) ] self.instances = [ self.new(FrameInstance, reader) for _ in xrange(reader.readInt()) ] self.events = self.new(Events, reader) self.chunks = self.new(ChunkList, reader) def write(self, reader): reader.writeInt(self.handle) reader.writeInt(len(self.name)) reader.write(self.name) reader.writeInt(self.size[0]) reader.writeInt(self.size[1]) reader.writeColor(self.background) reader.writeInt(self.flags.getFlags(), True) reader.writeInt(self.maxObjects) reader.writeInt(len(self.password)) reader.write(self.password) reader.writeInt(0) reader.writeInt(self.lastViewedX) reader.writeInt(self.lastViewedY) reader.writeInt(len(self.palette)) for item in self.palette: reader.writeColor(item) reader.writeInt(self.stampHandle) reader.writeInt(self.activeLayer) reader.writeInt(len(self.layers)) for item in self.layers: item.write(reader) for item in (self.fadeIn, self.fadeOut): if item is not None: reader.writeByte(1) item.write(reader) else: reader.writeByte(0) for item in (self.items, self.folders, self.instances): reader.writeInt(len(item), True) for subitem in item: subitem.write(reader) self.events.write(reader) self.chunks.write(reader)