# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ # ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ # ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ # ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ # ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ # Magicbane Emulator Project © 2013 - 2022 # www.magicbane.com from collections import OrderedDict from arcane.enums.arc_rune import * from arcane.enums.hashes import hash_to_string, string_to_hash from arcane.objects.ArcRune import Group from arcane.objects.common.Inventory import Inventory from arcane.util import ResStream from .ArcBasicZoneObjectInfo import ArcBasicZoneObjectInfo class Unknown: def load_binary(self, stream: ResStream): self.unknown_u = stream.read_dword() self.unknown_u = stream.read_dword() self.unknown_u = stream.read_dword() self.unknown_check = stream.read_bool() if self.unknown_check: self.unknown_u = stream.read_qword() else: self.unknown_u = stream.read_dword() self.unknown_u = stream.read_string() self.unknown_u = stream.read_float() class InventoryContents: def load_binary(self, stream: ResStream): self.mobile_inventory_u = stream.read_qword() self.mobile_inventory_u = stream.read_qword() self.mobile_inventory_u = stream.read_tuple() self.mobile_inventory_u = stream.read_tuple() self.mobile_inventory_u = [stream.read_float() for _ in range(4)] self.mobile_inventory_u = stream.read_qword() self.mobile_inventory_u = stream.read_dword() self.mobile_inventory_u = stream.read_dword() self.mobile_inventory_u = stream.read_dword() self.mobile_inventory_u = stream.read_bool() self.mobile_inventory_u = stream.read_string() self.mobile_inventory_check = stream.read_bool() if self.mobile_inventory_check: self.mobile_inventory_u = stream.read_float() self.mobile_inventory_u = stream.read_float() self.mobile_inventory_check = stream.read_bool() if self.mobile_inventory_check: self.mobile_inventory_u = stream.read_qword() self.mobile_inventory_u = stream.read_dword() self.mobile_inventory_u = stream.read_dword() self.mobile_inventory_u = stream.read_float() self.mobile_inventory_u = stream.read_dword() self.mobile_inventory_u = stream.read_dword() num = stream.read_dword() self.mobile_inventory_u = [Unknown() for _ in range(num)] self.mobile_inventory_u = stream.read_dword() self.mobile_inventory_check = stream.read_bool() if self.mobile_inventory_check: self.mobile_inventory_u = stream.read_qword() self.mobile_inventory_u = stream.read_qword() self.mobile_inventory_u = stream.read_qword() self.mobile_inventory_u = stream.read_dword() self.mobile_inventory_check = stream.read_bool() if self.mobile_inventory_check: self.mobile_inventory_u = stream.read_qword() self.mobile_inventory_u = stream.read_dword() self.mobile_inventory_check = stream.read_bool() if self.mobile_inventory_check: self.mobile_inventory_u = stream.read_bool() self.mobile_inventory_u = stream.read_float() self.mobile_inventory_u = stream.read_dword() self.mobile_inventory_u = stream.read_dword() self.mobile_inventory_check = stream.read_bool() if self.mobile_inventory_check: self.mobile_inventory_u = [stream.read_dword() for _ in range(5)] self.mobile_inventory_check = stream.read_bool() if self.mobile_inventory_check: self.mobile_inventory_u = [stream.read_dword() for _ in range(5)] self.mobile_inventory_u = stream.read_bool() class MobileInfo: def load_binary(self, stream: ResStream): self.mobile_base_zone = ArcBasicZoneObjectInfo() self.mobile_base_zone.load_binary(stream) self.mobile_number_in_group = stream.read_dword() self.mobile_change_to_find = stream.read_float() self.mobile_level = stream.read_dword() self.mobile_behavior_file = stream.read_string() self.mobile_dialog_override = stream.read_dword() self.mobile_base_exp_reward = stream.read_dword() self.mobile_tenacity = stream.read_float() self.mobile_courage = stream.read_float() self.mobile_has_group_tactics = stream.read_bool() if self.mobile_has_group_tactics: self.mobile_group_tactics = stream.read_dword() self.mobile_has_role_set = stream.read_bool() if self.mobile_has_role_set: self.mobile_role_set = stream.read_dword() self.mobile_has_home_goal = stream.read_bool() if self.mobile_has_home_goal: self.mobile_home_goal = stream.read_dword() self.mobile_spawn_home_goal = stream.read_bool() self.mobile_has_target_goal = stream.read_bool() if self.mobile_has_target_goal: self.mobile_target_goal = stream.read_dword() self.mobile_spawn_target_goal = stream.read_bool() num_rune_stone_ids = stream.read_dword() self.mobile_rune_stone_ids = [stream.read_qword() for _ in range(num_rune_stone_ids)] self.mobile_has_content = stream.read_bool() if self.mobile_has_content: num_contents = stream.read_dword() self.mobile_inventory_contents = [InventoryContents() for _ in range(num_contents)] for content in self.mobile_inventory_contents: content.load_binary(stream) num_equipments = stream.read_dword() self.mobile_equipment = [[ stream.read_qword(), stream.read_float(), ] for _ in range(num_equipments)] num_lores = stream.read_dword() self.mobile_lores = [stream.read_dword() for _ in range(num_lores)] self.mobile_use_prefered_hp = stream.read_bool() num_spawn_hps = stream.read_dword() self.mobile_spawn_hps = [stream.read_dword() for _ in range(num_spawn_hps)] num = stream.read_dword() self.mobile_booties = [Inventory() for _ in range(num)] for booty in self.mobile_booties: booty.load_binary(stream) self.mobile_root_fs_mid = stream.read_string() self.mobile_group = Group() self.mobile_group.load_binary(stream) num_enemy_monster_types = stream.read_dword() self.mobile_enemy_monster_types = [stream.read_dword() for _ in range(num_enemy_monster_types)] num_not_enemy_monster_types = stream.read_dword() self.mobile_not_enemy_monster_types = [stream.read_dword() for _ in range(num_not_enemy_monster_types)] num_groupee_monster_types = stream.read_dword() self.mobile_groupee_monster_types = [stream.read_dword() for _ in range(num_groupee_monster_types)] num_helper_monster_types = stream.read_dword() self.mobile_helper_monster_types = [stream.read_dword() for _ in range(num_helper_monster_types)] num_enemy_genders = stream.read_dword() self.mobile_enemy_genders = [stream.read_dword() for _ in range(num_enemy_genders)] num_friendly_charters = stream.read_dword() self.mobile_friendly_charters = [stream.read_dword() for _ in range(num_friendly_charters)] self.mobile_parley_name = stream.read_string() def save_binary(self, stream: ResStream): self.mobile_base_zone.save_binary(stream) stream.write_dword(self.mobile_number_in_group) stream.write_float(self.mobile_change_to_find) stream.write_dword(self.mobile_level) stream.write_string(self.mobile_behavior_file) stream.write_dword(self.mobile_dialog_override) stream.write_dword(self.mobile_base_exp_reward) stream.write_float(self.mobile_tenacity) stream.write_float(self.mobile_courage) stream.write_bool(self.mobile_has_group_tactics) if self.mobile_has_group_tactics: stream.write_dword(self.mobile_group_tactics) stream.write_bool(self.mobile_has_role_set) if self.mobile_has_role_set: stream.write_dword(self.mobile_role_set) stream.write_bool(self.mobile_has_home_goal) if self.mobile_has_home_goal: stream.write_dword(self.mobile_home_goal) stream.write_bool(self.mobile_spawn_home_goal) stream.write_bool(self.mobile_has_target_goal) if self.mobile_has_target_goal: stream.write_dword(self.mobile_target_goal) stream.write_bool(self.mobile_spawn_target_goal) stream.write_dword(len(self.mobile_rune_stone_ids)) for rune_stone_id in self.mobile_rune_stone_ids: stream.write_qword(rune_stone_id) stream.write_bool(self.mobile_has_content) if self.mobile_has_content: stream.write_dword(len(self.mobile_inventory_contents)) for content in self.mobile_inventory_contents: content.save_binary(stream) stream.write_dword(len(self.mobile_equipment)) for equipment in self.mobile_equipment: stream.write_qword(equipment[0]) stream.write_float(equipment[1]) stream.write_dword(len(self.mobile_lores)) for lore in self.mobile_lores: stream.write_dword(lore) stream.write_bool(self.mobile_use_prefered_hp) stream.write_dword(len(self.mobile_spawn_hps)) for spawn_hp in self.mobile_spawn_hps: stream.write_dword(spawn_hp) stream.write_dword(len(self.mobile_booties)) for booty in self.mobile_booties: booty.save_binary(stream) stream.write_string(self.mobile_root_fs_mid) self.mobile_group.save_binary(stream) stream.write_dword(len(self.mobile_enemy_monster_types)) for enemy_monster_type in self.mobile_enemy_monster_types: stream.write_dword(enemy_monster_type) stream.write_dword(len(self.mobile_not_enemy_monster_types)) for not_enemy_monster_type in self.mobile_not_enemy_monster_types: stream.write_dword(not_enemy_monster_type) stream.write_dword(len(self.mobile_groupee_monster_types)) for groupee_monster_type in self.mobile_groupee_monster_types: stream.write_dword(groupee_monster_type) stream.write_dword(len(self.mobile_helper_monster_types)) for helper_monster_type in self.mobile_helper_monster_types: stream.write_dword(helper_monster_type) stream.write_dword(len(self.mobile_enemy_genders)) for enemy_gender in self.mobile_enemy_genders: stream.write_dword(enemy_gender) stream.write_dword(len(self.mobile_friendly_charters)) for friendly_charter in self.mobile_friendly_charters: stream.write_dword(friendly_charter) stream.write_string(self.mobile_parley_name) def save_json(self): data = OrderedDict() data['mobile_base_zone'] = self.mobile_base_zone.save_json() data['mobile_number_in_group'] = self.mobile_number_in_group data['mobile_change_to_find'] = self.mobile_change_to_find data['mobile_level'] = self.mobile_level data['mobile_behavior_file'] = self.mobile_behavior_file data['mobile_dialog_override'] = self.mobile_dialog_override data['mobile_base_exp_reward'] = self.mobile_base_exp_reward data['mobile_tenacity'] = self.mobile_tenacity data['mobile_courage'] = self.mobile_courage data['mobile_has_group_tactics'] = self.mobile_has_group_tactics if self.mobile_has_group_tactics: data['mobile_group_tactics'] = self.mobile_group_tactics data['mobile_has_role_set'] = self.mobile_has_role_set if self.mobile_has_role_set: data['mobile_role_set'] = self.mobile_role_set data['mobile_has_home_goal'] = self.mobile_has_home_goal if self.mobile_has_home_goal: data['mobile_home_goal'] = self.mobile_home_goal data['mobile_spawn_home_goal'] = self.mobile_spawn_home_goal data['mobile_has_target_goal'] = self.mobile_has_target_goal if self.mobile_has_target_goal: data['mobile_target_goal'] = self.mobile_target_goal data['mobile_spawn_target_goal'] = self.mobile_spawn_target_goal data['mobile_rune_stone_ids'] = self.mobile_rune_stone_ids data['mobile_has_content'] = self.mobile_has_content if self.mobile_has_content: data['mobile_inventory_contents'] = [] for content in self.mobile_inventory_contents: data['mobile_inventory_contents'].append(content.save_json()) data['mobile_equipment'] = self.mobile_equipment data['mobile_lores'] = self.mobile_lores data['mobile_use_prefered_hp'] = self.mobile_use_prefered_hp data['mobile_spawn_hps'] = self.mobile_spawn_hps data['mobile_booties'] = [] for booty in self.mobile_booties: data['mobile_booties'].append(booty.save_json()) data['mobile_root_fs_mid'] = self.mobile_root_fs_mid data['mobile_group'] = self.mobile_group.save_json() data['mobile_enemy_monster_types'] = [] for enemy_monster_type in self.mobile_enemy_monster_types: data['mobile_enemy_monster_types'].append(hash_to_string(enemy_monster_type)) data['mobile_not_enemy_monster_types'] = [] for not_enemy_monster_type in self.mobile_not_enemy_monster_types: data['mobile_not_enemy_monster_types'].append(hash_to_string(not_enemy_monster_type)) data['mobile_groupee_monster_types'] = [] for groupee_monster_type in self.mobile_groupee_monster_types: data['mobile_groupee_monster_types'].append(hash_to_string(groupee_monster_type)) data['mobile_helper_monster_types'] = [] for helper_monster_type in self.mobile_helper_monster_types: data['mobile_helper_monster_types'].append(hash_to_string(helper_monster_type)) data['mobile_enemy_genders'] = [] for enemy_gender in self.mobile_enemy_genders: data['mobile_enemy_genders'].append(RUNE_SEX_TO_STRING[enemy_gender]) data['mobile_friendly_charters'] = self.mobile_friendly_charters data['mobile_parley_name'] = self.mobile_parley_name return data def load_json(self, data): self.mobile_base_zone = ArcBasicZoneObjectInfo() self.mobile_base_zone.load_json(data['mobile_base_zone']) self.mobile_number_in_group = data['mobile_number_in_group'] self.mobile_change_to_find = data['mobile_change_to_find'] self.mobile_level = data['mobile_level'] self.mobile_behavior_file = data['mobile_behavior_file'] self.mobile_dialog_override = data['mobile_dialog_override'] self.mobile_base_exp_reward = data['mobile_base_exp_reward'] self.mobile_tenacity = data['mobile_tenacity'] self.mobile_courage = data['mobile_courage'] self.mobile_has_group_tactics = data['mobile_has_group_tactics'] if self.mobile_has_group_tactics: self.mobile_group_tactics = data['mobile_group_tactics'] self.mobile_has_role_set = data['mobile_has_role_set'] if self.mobile_has_role_set: self.mobile_role_set = data['mobile_role_set'] self.mobile_has_home_goal = data['mobile_has_home_goal'] if self.mobile_has_home_goal: self.mobile_home_goal = data['mobile_home_goal'] self.mobile_spawn_home_goal = data['mobile_spawn_home_goal'] self.mobile_has_target_goal = data['mobile_has_target_goal'] if self.mobile_has_target_goal: self.mobile_target_goal = data['mobile_target_goal'] self.mobile_spawn_target_goal = data['mobile_spawn_target_goal'] self.mobile_rune_stone_ids = data['mobile_rune_stone_ids'] self.mobile_has_content = data['mobile_has_content'] if self.mobile_has_content: self.mobile_inventory_contents = [] for content_data in data['mobile_inventory_contents']: content = InventoryContents() content.load_json(content_data) self.mobile_inventory_contents.append(content) self.mobile_equipment = data['mobile_equipment'] self.mobile_lores = data['mobile_lores'] self.mobile_use_prefered_hp = data['mobile_use_prefered_hp'] self.mobile_spawn_hps = data['mobile_spawn_hps'] self.mobile_booties = [] for booty_data in data['mobile_booties']: booty = Inventory() booty.load_json(booty_data) self.mobile_booties.append(booty) self.mobile_root_fs_mid = data['mobile_root_fs_mid'] self.mobile_group = Group() self.mobile_group.load_json(data['mobile_group']) self.mobile_enemy_monster_types = [] for enemy_monster_type in data['mobile_enemy_monster_types']: self.mobile_enemy_monster_types.append(string_to_hash(enemy_monster_type)) self.mobile_not_enemy_monster_types = [] for not_enemy_monster_type in data['mobile_not_enemy_monster_types']: self.mobile_not_enemy_monster_types.append(string_to_hash(not_enemy_monster_type)) self.mobile_groupee_monster_types = [] for groupee_monster_type in data['mobile_groupee_monster_types']: self.mobile_groupee_monster_types.append(string_to_hash(groupee_monster_type)) self.mobile_helper_monster_types = [] for helper_monster_type in data['mobile_helper_monster_types']: self.mobile_helper_monster_types.append(string_to_hash(helper_monster_type)) self.mobile_enemy_genders = [] for enemy_gender in data['mobile_enemy_genders']: self.mobile_enemy_genders.append(STRING_TO_RUNE_SEX[enemy_gender]) self.mobile_friendly_charters = data['mobile_friendly_charters'] self.mobile_parley_name = data['mobile_parley_name']