def __init__(self, idx_filename, mul_filename, length, file_idx): try: index_file = None self.index_file_path = ultima_file_path(idx_filename) index_file = open(self.index_file_path, 'rb') self.mul_file_path = ultima_file_path(mul_filename) except FileNotFoundError: print( f"No file for index {idx_filename if not index_file else mul_filename}" ) return idx_file_bytes = len(index_file.read()) index_file.seek(0) count = int(idx_file_bytes / 12) length = length or count self.index_length = idx_file_bytes self.index = [] for i in range(count): self.index.append(Entry3D(*unpack('i' * 3, index_file.read(4 * 3)))) for i in range(count, length): self.index.append(Entry3D(-1, -1, -1)) patches = Verdata.patches if file_idx > -1: for idx, patch in enumerate(patches): if patch.file == file_idx and 0 < patch.index < length: self.index[patch.index].lookup = patch.lookup self.index[patch.index].length = patch.length | (1 << 31) self.index[patch.index].extra = patch.extra
def load(cls): cls.file_index = FileIndex(ultima_file_path('Skills.idx'), ultima_file_path('skills.mul'), None, 16) for i in range(cls.file_index.index_length): stream, length, extra, patched = cls.file_index.seek(i) if stream is None: continue is_action = unpack('?', stream.read(1))[0] name = unpack(f'{(length-1)}s', stream.read(length - 1))[0].decode('cp1252')[:-1] cls.entries.append(SkillInfo(i, name, is_action, extra))
def load(cls): def read_char(): return unpack( 'c', f.read(1))[0].decode('cp1252') if not cls.unicode else chr( unpack('h', f.read(2))[0]) Skills.load() with open(ultima_file_path('skillgrp.mul'), 'rb') as f: start = 4 strlen = 17 count = unpack('i', f.read(4))[0] if count == -1: cls.unicode = True count = unpack('i', f.read(4))[0] start *= 2 strlen *= 2 cls.categories.append("Misc") for i in range(count - 1): f.seek(start + (i * strlen)) name = '' c = read_char() while c != '\x00': name += c c = read_char() cls.categories.append(name) f.seek(start + (count - 1) * strlen) skill_num = unpack('i', f.read(4))[0] for i, skill in enumerate(Skills.entries): skill.category = cls.categories[skill_num] try: skill_num = unpack('i', f.read(4))[0] except error: break
def load(cls): cls.loaded = True with open(ultima_file_path('tiledata.mul'), 'rb') as f: f.seek(0, 2) length = f.tell() f.seek(0) cls.new_format = Art.is_uoahs j = 0 for i in range(0, len(cls.land_data), 32): cls.land_header[j] = unpack('i', f.read(4))[0] j += 1 for count in range(32): mul_type = NewLandMul if cls.new_format else OldLandMul cls.land_data[i + count] = mul_type.from_stream(f) remaining = length - f.tell() mul_type = NewItemMul if cls.new_format else OldItemMul cls.item_header = [0] * int(remaining / (mul_type.size * 32 + 4)) item_length = len(cls.item_header) * 32 cls.item_data = [None] * item_length cls.height_table = [0] * item_length j = 0 for i in range(0, item_length, 32): cls.item_header[j] = unpack('i', f.read(4))[0] j += 1 for count in range(32): cls.item_data[i + count] = mul_type.from_stream(f)
def load(cls): with open(ultima_file_path('fonts.mul'), 'rb') as f: for i in range(10): font = ASCIIFont(f) for k in range(224): width = read_byte(f) height = read_byte(f) read_byte(f) # unknown, discard if k < 96: font.height = max(font.height, height) img = Image.new("RGBA", (width, height), (0, 0, 0, 0)) pos = f.tell() stride = 2 * width # 2 bytes, width for y in range(height): f.seek(pos) pos += stride for x in range(width): first_byte = read_byte(f) second_byte = read_byte(f) pixel_num = first_byte | (second_byte << 8) if pixel_num > 0: img.putpixel( (x, y), get_arbg_from_16_bit(pixel_num ^ 0x8000)) font.add_character(chr(k + 32), img)
def load(cls): print("Loading BodyConverter") f = open(ultima_file_path('Bodyconv.def'), 'r') max1 = max2 = max3 = max4 = 0 list1 = [] list2 = [] list3 = [] list4 = [] for line in f: line = line.strip() if not line or line.startswith("#"): continue fields = line.split("\t") try: orig = int(safe_list_get(fields, 0, -1)) anim2 = int(safe_list_get(fields, 1, -1)) anim3 = int(safe_list_get(fields, 2, -1)) anim4 = int(safe_list_get(fields, 3, -1)) anim5 = int(safe_list_get(fields, 4, -1)) except: continue if anim2 >= 0: anim2 = 122 if anim2 == 68 else anim2 max1 = max(max1, orig) list1.append(orig) list1.append(anim2) if anim3 >= 0: max2 = max(max2, orig) list2.append(orig) list2.append(anim3) if anim4 >= 0: max3 = max(max3, orig) list3.append(orig) list3.append(anim4) if anim5 >= 0: max4 = max(max4, orig) list4.append(orig) list4.append(anim5) cls.TABLE_1 = [-1 for i in range(max1 + 1)] cls.TABLE_2 = [-1 for i in range(max2 + 1)] cls.TABLE_3 = [-1 for i in range(max3 + 1)] cls.TABLE_4 = [-1 for i in range(max4 + 1)] for i in range(0, len(list1), 2): cls.TABLE_1[list1[i]] = list1[i + 1] for i in range(0, len(list2), 2): cls.TABLE_2[list2[i]] = list2[i + 1] for i in range(0, len(list3), 2): cls.TABLE_3[list3[i]] = list3[i + 1] for i in range(0, len(list4), 2): cls.TABLE_4[list4[i]] = list4[i + 1] cls.loaded = True
class Verdata: """ No reason to instantiate. Assumed to be working as per C# Ultima SDK but untested. """ FILE = open(ultima_file_path('verdata.mul'), 'rb') patches = [] @classmethod def load(cls): total_patches = unpack('i', cls.FILE.read(4))[0] for i in range(total_patches): cls.patches.append(Entry5D(*unpack('i' * 5, cls.FILE.read(20)))) @classmethod def seek(cls, lookup): cls.FILE.Seek(lookup)
def load(cls): print("Loading Hues") cls.HUES = {i: Hue(i) for i in range(3000)} f = open(ultima_file_path('hues.mul'), 'rb') block_count = max(375, int(unpack('i', f.read(4))[0] / 708)) f.seek(0) headers = [] # why? idx = 0 for i in range(block_count): headers.append(unpack('i', f.read(4))) for j in range(8): new_hue = Hue(idx) new_hue.colors = [x | 0x8000 for x in unpack('H'*32, f.read(64))] new_hue.table_start, new_hue.table_end = unpack('hh', f.read(4)) new_hue.name = f.read(20).decode('cp1252') cls.HUES[idx] = new_hue idx += 1
def load(cls): print("Loading BodyTable") f = open(ultima_file_path('Body.def'), 'r') for line in f: line = line.strip() if not line or line.startswith("#"): continue # ultima sdk try catches this, but there are no exceptions thrown index1 = line.index("{") index2 = line.index("}") param1 = line[:index1].strip() param2 = line[index1 + 1:index2] param3 = line[index2 + 1:].strip() if "," in param2: param2 = param2[:param2.index(",")].strip() cls.entries[int(param1)] = BodyTableEntry(int(param2), int(param1), int(param3))