def _read_block_table(self, f, size): block_struct = 'HBBBBBB' self.block_table = [] for i in range(size / calcsize(block_struct)): block = Block(*unpack_file(block_struct, f)) self.block_table.append(block)
def _read_object_positions(self, f, size): object_pos_struct = 'HHHBBHHH' block_size = calcsize(object_pos_struct) self.object_pos = [] for i in range(size / block_size): data = unpack_file(object_pos_struct, f) self.object_pos.append(ObjectPos(*data))
def _read_navigation_data(self, f, size): nav_struct = 'BBBBB30s' self.districts = [] f.seek(-size, os.SEEK_END) for i in range(size / calcsize(nav_struct)): data = unpack_file(nav_struct, f) self.districts.append(District(*data))
def read_palettes(self, data, size): data = StringIO.StringIO(data) palette_count = size / 1024 self.palettes = [[] for i in range(palette_count)] for k in range(palette_count / 64): for j in range(256): for i in range(64): b, g, r, x = unpack_file('BBBB', data) self.palettes[k*64+i].extend((r, g, b)) k = palette_count / 64 for j in range(256): for i in range(palette_count % 64): b, g, r, x = unpack_file('BBBB', data) self.palettes[k*64 + i].extend((r, g, b))
def _read_grid(self, f): grid_columns = unpack_file('I' * 256 * 256, f) column_iter = iter(unpack_file('H' * (self.column_size / 2), f)) cube_stack_table = {} pos = 0 try: while True: d = column_iter.next() cubes = 6 - d cube_stack_table[pos] = [column_iter.next() for i in range(cubes)] pos += 2 * (1 + cubes) except StopIteration: pass self.grid = [] for column in grid_columns: stack = cube_stack_table[column] self.grid.append(stack)
def _read_object_info(self, f, size): ObjectInfo = namedtuple('ObjectInfo', 'width height depth sprite_num') object_info_struct = 'IIIHxxxxxx' block_size = calcsize(object_info_struct) self.object_infos = [] for i in range(size / block_size): data = unpack_file('IIIHxxxxxx', f) self.object_infos.append(ObjectInfo(*data)) print "object infos:", len(self.object_infos)
def _read_sprite_numbers(self, f, size): fields = 'arrow digits boat bux bus car object ped speedo tank ' \ 'traffic_lights train trdoors bike tram wbus wcar ex ' \ 'tumcar tumtruck ferry' SpriteNumbers = namedtuple('SpriteNumbers', fields) self.sprite_numbers = SpriteNumbers(*unpack_file('H' * (size / 2), f)) self.sprite_offset = {} for i, field in enumerate(SpriteNumbers._fields): fields_before = SpriteNumbers._fields[:i] self.sprite_offset[field] = sum(getattr(self.sprite_numbers, f) for f in fields_before) print "sprite numbers: ", ', '.join(("%d %s" % (v, k) for (k, v) in self.sprite_numbers._asdict().items()))
def load_from_file(self, f): # Header self.version, self.side_size, self.lid_size, self.aux_size, \ self.anim_size, self.clut_size, self.tileclut_size, self.spriteclut_size, \ self.newcarclut_size, self.fontclut_size, self.palette_index_size, \ self.object_info_size, self.car_size, self.sprite_info_size, \ self.sprite_graphics_size, self.sprite_numbers_size = unpack_file('I' * 16, f) # Tiles size = self.side_size + self.lid_size + self.aux_size if size % (64 * 64 * 4): size += (64 * 64 * 4) - (size % (64 * 64 * 4)) side_lid_aux = f.read(size) # Animations self._read_animations(f, self.anim_size) # Palette clut = f.read(self.clut_size) if self.clut_size % (64 * 1024): f.read(64*1024 - (self.clut_size % (64*1024))) palette_index_data = f.read(self.palette_index_size) self.palette_index = PaletteIndex(tile_index_size=self.tileclut_size / 1024) self.palette_index.read_palettes(clut, self.clut_size) self.palette_index.read_index(palette_index_data, self.palette_index_size) # Object infos self._read_object_info(f, self.object_info_size) # Car infos self._read_car_infos(f, self.car_size) # Sprites sprite_info = f.read(self.sprite_info_size) sprite_graphics = f.read(self.sprite_graphics_size) self._read_sprite_numbers(f, self.sprite_numbers_size) self.sprites = Sprite(StringIO.StringIO(sprite_info), sprite_graphics, self.palette_index) self.sprites.colorize() self.colorize_tiles(side_lid_aux, self.palette_index)
def load_from_file(self, f): self.version, self.style_number, self.sample, _, self.route_size, \ self.object_pos_size, self.column_size, self.block_size, \ self.nav_data_size = unpack_file('IBBHIIIII', f) self._read_grid(f) self._read_block_table(f, self.block_size) self._read_object_positions(f, self.object_pos_size) self._read_navigation_data(f, self.nav_data_size) self.style = Style() self.style.load_from_file(open('data/STYLE00%d.G24' % self.style_number)) # The lid attribute in a block stores a relative offset into the lid tiles. # By making it absolute, it becomes easier to work with on the client. lid_tile_offset = self.style.side_size / (64 * 64) for i in range(len(self.block_table)): block = self.block_table[i] if block.lid: block = block._replace(lid=block.lid + lid_tile_offset) self.block_table[i] = block
def _read_car_infos(self, f, size): fields = 'width height depth sprite_num weight max_speed min_speed acceleration braking grip handling ' \ 'remap24 remap8 ' \ 'vtype model turning damageable value mass_center_x mass_center_y moment ' \ 'rbp_mass g1_thrust tyre_adhesion_x tyre_adhesion_y handbrake_friction footbrake_friction front_brake_bias ' \ 'turn_ratio drive_wheel_offset ' \ 'back_end_slide_value handbrake_slide_value ' \ 'convertible engine radio horn sound_function fast_change_flag door_count doors' CarInfo = namedtuple('CarInfo', fields) hls_info_struct = 'hhh' door_info_struct = 'HHHH' fixed_to_float = lambda x: x * (1.0 / 2**16) start = f.tell() self.car_infos = [] while f.tell() < start + size: data = list(unpack_file('hhhhhhhhhhh', f)) data += [[unpack_file(hls_info_struct, f) for i in range(12)]] data += [unpack_file('B' * 12, f)] data += unpack_file('BBBB', f) data += [unpack_file('HHHH', f)] data += unpack_file('bb i', f) data += map(fixed_to_float, unpack_file('iiiiiii', f)) data += unpack_file('hh', f) data += map(fixed_to_float, unpack_file('ii', f)) data += unpack_file('BBBBBB', f) door_count, = unpack_file('h', f) doors = [] for j in range(door_count): doors.append(unpack_file('hhhh', f)) data += [door_count, doors] self.car_infos.append(CarInfo(*data)) print "car infos:", len(self.car_infos)