You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
469 lines
21 KiB
469 lines
21 KiB
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
|
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
|
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
|
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
|
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
|
# 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.util import ResStream |
|
from .ArcItem import ArcItem |
|
from .common.Arcane import AttributeValue, SkillGrant |
|
from .common.Inventory import Inventory |
|
from .common.SparseData import SparseData |
|
|
|
|
|
class Group: |
|
def load_binary(self, stream: ResStream): |
|
self.group_type = stream.read_dword() |
|
self.group_is_faction = stream.read_bool() |
|
self.group_is_guild = stream.read_bool() |
|
|
|
def save_binary(self, stream: ResStream): |
|
stream.write_dword(self.group_type) |
|
stream.write_bool(self.group_is_faction) |
|
stream.write_bool(self.group_is_guild) |
|
|
|
def load_json(self, data): |
|
self.group_type = data['group_type'] |
|
self.group_is_faction = data['group_is_faction'] |
|
self.group_is_guild = data['group_is_guild'] |
|
|
|
def save_json(self): |
|
data = OrderedDict() |
|
data['group_type'] = self.group_type |
|
data['group_is_faction'] = self.group_is_faction |
|
data['group_is_guild'] = self.group_is_guild |
|
return data |
|
|
|
|
|
class SkillAdjust: |
|
def load_binary(self, stream: ResStream): |
|
self.skill_type = stream.read_dword() |
|
|
|
num_adjusts = stream.read_dword() |
|
self.skill_adjusts = [ |
|
[ |
|
stream.read_dword(), |
|
stream.read_dword(), |
|
] for _ in range(num_adjusts) |
|
] |
|
|
|
def save_binary(self, stream: ResStream): |
|
stream.write_dword(self.skill_type) |
|
stream.write_dword(len(self.skill_adjusts)) |
|
for skill in self.skill_adjusts: |
|
stream.write_dword(skill[0]) |
|
stream.write_dword(skill[1]) |
|
|
|
def load_json(self, data): |
|
self.skill_type = string_to_hash(data['skill_type']) |
|
self.skill_adjusts = [] |
|
for skill in data['skill_adjusts']: |
|
self.skill_adjusts.append(skill) |
|
|
|
def save_json(self): |
|
data = OrderedDict() |
|
data['skill_type'] = hash_to_string(self.skill_type) |
|
data['skill_adjusts'] = [] |
|
for skill in self.skill_adjusts: |
|
data['skill_adjusts'].append(skill) |
|
return data |
|
|
|
|
|
class BodyPart: |
|
def load_binary(self, stream: ResStream): |
|
self.body_part_render = stream.read_qword() |
|
self.body_part_position = stream.read_tuple() |
|
|
|
def save_binary(self, stream: ResStream): |
|
stream.write_qword(self.body_part_render) |
|
stream.write_tuple(self.body_part_position) |
|
|
|
def load_json(self, data): |
|
self.body_part_render = data['body_part_render'] |
|
self.body_part_position = data['body_part_position'] |
|
|
|
def save_json(self): |
|
data = OrderedDict() |
|
data['body_part_render'] = self.body_part_render |
|
data['body_part_position'] = self.body_part_position |
|
return data |
|
|
|
|
|
class ArcRune(ArcItem): |
|
def load_binary(self, stream: ResStream): |
|
super().load_binary(stream) |
|
self.rune_type = stream.read_dword() |
|
self.rune_sub_type = stream.read_dword() |
|
self.rune_is_standard_character_creation = stream.read_bool() |
|
self.rune_creation_cost = stream.read_dword() |
|
self.rune_rank = stream.read_dword() |
|
self.rune_pracs_per_level = stream.read_dword() |
|
self.rune_exp_req_to_level = stream.read_float() |
|
self.rune_sex = stream.read_dword() |
|
self.rune_class_icon = stream.read_qword() |
|
self.rune_health = stream.read_dword() |
|
self.rune_mana = stream.read_dword() |
|
self.rune_stamina = stream.read_dword() |
|
self.rune_min_damage = stream.read_float() |
|
self.rune_max_damage = stream.read_float() |
|
self.rune_attack = stream.read_dword() |
|
self.rune_defense = stream.read_dword() |
|
self.rune_level = stream.read_dword() |
|
self.rune_speed = [ |
|
stream.read_float() for _ in range(7) |
|
] |
|
self.rune_group = Group() |
|
self.rune_group.load_binary(stream) |
|
self.rune_dsc = stream.read_string() |
|
self.rune_fx_txt = stream.read_string() |
|
self.rune_group_tactics = stream.read_dword() |
|
self.rune_group_role_set = stream.read_dword() |
|
num_enemies = stream.read_dword() |
|
self.rune_enemy_monster_types = [ |
|
stream.read_dword() for _ in range(num_enemies) |
|
] |
|
num_groupees = stream.read_dword() |
|
self.rune_groupee_monster_types = [ |
|
stream.read_dword() for _ in range(num_groupees) |
|
] |
|
num_helpers = stream.read_dword() |
|
self.rune_helper_monster_types = [ |
|
stream.read_dword() for _ in range(num_helpers) |
|
] |
|
num_not_enemies = stream.read_dword() |
|
self.rune_not_enemy_monster_types = [ |
|
stream.read_dword() for _ in range(num_not_enemies) |
|
] |
|
num_genders = stream.read_dword() |
|
self.rune_enemy_gender = [ |
|
stream.read_dword() for _ in range(num_genders) |
|
] |
|
num_skill_grants = stream.read_dword() |
|
self.rune_skill_grant = [SkillGrant() for _ in range(num_skill_grants)] |
|
for grant in self.rune_skill_grant: |
|
grant.load_binary(stream) |
|
num_skill_adjusts = stream.read_dword() |
|
self.rune_skill_adj = [SkillAdjust() for _ in range(num_skill_adjusts)] |
|
for adjust in self.rune_skill_adj: |
|
adjust.load_binary(stream) |
|
num_attr_adjusts = stream.read_dword() |
|
self.rune_attr_adj = [AttributeValue() for _ in range(num_attr_adjusts)] |
|
for attr in self.rune_attr_adj: |
|
attr.load_binary(stream) |
|
num_max_attr_adjusts = stream.read_dword() |
|
self.rune_max_attr_adj = [AttributeValue() for _ in range(num_max_attr_adjusts)] |
|
for attr in self.rune_max_attr_adj: |
|
attr.load_binary(stream) |
|
num_natural_attacks = stream.read_dword() |
|
self.rune_naturalattacks = [ |
|
[ |
|
stream.read_float(), |
|
stream.read_float(), |
|
stream.read_dword(), |
|
stream.read_dword(), |
|
stream.read_qword(), |
|
stream.read_float(), |
|
stream.read_dword(), |
|
stream.read_dword(), |
|
stream.read_dword(), |
|
stream.read_dword(), |
|
] for _ in range(num_natural_attacks) |
|
] |
|
num_enchants = stream.read_dword() |
|
self.rune_enchantment_type = [ |
|
stream.read_dword() for _ in range(num_enchants) |
|
] |
|
num_contents = stream.read_dword() |
|
self.rune_inventory_contents = [Inventory() for _ in range(num_contents)] |
|
for content in self.rune_inventory_contents: |
|
content.load_binary(stream) |
|
|
|
self.rune_renderable = stream.read_bool() |
|
if self.rune_renderable: |
|
self.rune_scale_factor = stream.read_tuple() |
|
self.rune_skeleton = stream.read_qword() |
|
self.rune_slope_hugger = stream.read_bool() |
|
self.rune_can_fly = stream.read_bool() |
|
self.rune_death_effect = stream.read_qword() |
|
self.rune_tombstone_id = stream.read_qword() |
|
num_body_parts = stream.read_dword() |
|
self.rune_body_parts = [BodyPart() for _ in range(num_body_parts)] |
|
for part in self.rune_body_parts: |
|
part.load_binary(stream) |
|
num_hair = stream.read_dword() |
|
self.rune_hair = [ |
|
stream.read_qword() for _ in range(num_hair) |
|
] |
|
num_beard = stream.read_dword() |
|
self.rune_beard = [ |
|
stream.read_qword() for _ in range(num_beard) |
|
] |
|
self.rune_natural_power_attack = stream.read_dword() |
|
self.rune_sparse_data = SparseData() |
|
self.rune_sparse_data.load_binary(stream) |
|
|
|
def save_binary(self, stream: ResStream): |
|
super().save_binary(stream) |
|
stream.write_dword(self.rune_type) |
|
stream.write_dword(self.rune_sub_type) |
|
stream.write_bool(self.rune_is_standard_character_creation) |
|
stream.write_dword(self.rune_creation_cost) |
|
stream.write_dword(self.rune_rank) |
|
stream.write_dword(self.rune_pracs_per_level) |
|
stream.write_float(self.rune_exp_req_to_level) |
|
stream.write_dword(self.rune_sex) |
|
stream.write_qword(self.rune_class_icon) |
|
stream.write_dword(self.rune_health) |
|
stream.write_dword(self.rune_mana) |
|
stream.write_dword(self.rune_stamina) |
|
stream.write_float(self.rune_min_damage) |
|
stream.write_float(self.rune_max_damage) |
|
stream.write_dword(self.rune_attack) |
|
stream.write_dword(self.rune_defense) |
|
stream.write_dword(self.rune_level) |
|
for i in range(7): |
|
stream.write_float(self.rune_speed[i]) |
|
self.rune_group.save_binary(stream) |
|
stream.write_string(self.rune_dsc) |
|
stream.write_string(self.rune_fx_txt) |
|
stream.write_dword(self.rune_group_tactics) |
|
stream.write_dword(self.rune_group_role_set) |
|
stream.write_dword(len(self.rune_enemy_monster_types)) |
|
for monster in self.rune_enemy_monster_types: |
|
stream.write_dword(monster) |
|
stream.write_dword(len(self.rune_groupee_monster_types)) |
|
for monster in self.rune_groupee_monster_types: |
|
stream.write_dword(monster) |
|
stream.write_dword(len(self.rune_helper_monster_types)) |
|
for monster in self.rune_helper_monster_types: |
|
stream.write_dword(monster) |
|
stream.write_dword(len(self.rune_not_enemy_monster_types)) |
|
for monster in self.rune_not_enemy_monster_types: |
|
stream.write_dword(monster) |
|
stream.write_dword(len(self.rune_enemy_gender)) |
|
for gender in self.rune_enemy_gender: |
|
stream.write_dword(gender) |
|
stream.write_dword(len(self.rune_skill_grant)) |
|
for grant in self.rune_skill_grant: |
|
grant.save_binary(stream) |
|
stream.write_dword(len(self.rune_skill_adj)) |
|
for adjust in self.rune_skill_adj: |
|
adjust.save_binary(stream) |
|
stream.write_dword(len(self.rune_attr_adj)) |
|
for attr in self.rune_attr_adj: |
|
attr.save_binary(stream) |
|
stream.write_dword(len(self.rune_max_attr_adj)) |
|
for attr in self.rune_max_attr_adj: |
|
attr.save_binary(stream) |
|
stream.write_dword(len(self.rune_naturalattacks)) |
|
for attack in self.rune_naturalattacks: |
|
stream.write_float(attack[0]) |
|
stream.write_float(attack[1]) |
|
stream.write_dword(attack[2]) |
|
stream.write_dword(attack[3]) |
|
stream.write_qword(attack[4]) |
|
stream.write_float(attack[5]) |
|
stream.write_dword(attack[6]) |
|
stream.write_dword(attack[7]) |
|
stream.write_dword(attack[8]) |
|
stream.write_dword(attack[9]) |
|
stream.write_dword(len(self.rune_enchantment_type)) |
|
for enchantment in self.rune_enchantment_type: |
|
stream.write_dword(enchantment) |
|
stream.write_dword(len(self.rune_inventory_contents)) |
|
for content in self.rune_inventory_contents: |
|
content.save_binary(stream) |
|
stream.write_bool(self.rune_renderable) |
|
if self.rune_renderable: |
|
stream.write_tuple(self.rune_scale_factor) |
|
stream.write_qword(self.rune_skeleton) |
|
stream.write_bool(self.rune_slope_hugger) |
|
stream.write_bool(self.rune_can_fly) |
|
stream.write_qword(self.rune_death_effect) |
|
stream.write_qword(self.rune_tombstone_id) |
|
stream.write_dword(len(self.rune_body_parts)) |
|
for part in self.rune_body_parts: |
|
part.save_binary(stream) |
|
stream.write_dword(len(self.rune_hair)) |
|
for hair in self.rune_hair: |
|
stream.write_qword(hair) |
|
stream.write_dword(len(self.rune_beard)) |
|
for beard in self.rune_beard: |
|
stream.write_qword(beard) |
|
stream.write_dword(self.rune_natural_power_attack) |
|
self.rune_sparse_data.save_binary(stream) |
|
|
|
def load_json(self, data): |
|
super().load_json(data) |
|
self.rune_type = STRING_TO_RUNE_TYPE[data['rune_type']] |
|
self.rune_sub_type = string_to_hash(data['rune_sub_type']) |
|
self.rune_is_standard_character_creation = data['rune_is_standard_character_creation'] |
|
self.rune_creation_cost = data['rune_creation_cost'] |
|
self.rune_rank = data['rune_rank'] |
|
self.rune_pracs_per_level = data['rune_pracs_per_level'] |
|
self.rune_exp_req_to_level = data['rune_exp_req_to_level'] |
|
self.rune_sex = STRING_TO_RUNE_SEX[data['rune_sex']] |
|
self.rune_class_icon = data['rune_class_icon'] |
|
self.rune_health = data['rune_health'] |
|
self.rune_mana = data['rune_mana'] |
|
self.rune_stamina = data['rune_stamina'] |
|
self.rune_min_damage = data['rune_min_damage'] |
|
self.rune_max_damage = data['rune_max_damage'] |
|
self.rune_attack = data['rune_attack'] |
|
self.rune_defense = data['rune_defense'] |
|
self.rune_level = data['rune_level'] |
|
self.rune_speed = [] |
|
for i in range(7): |
|
self.rune_speed.append(data['rune_speed'][SPEED_TYPE_TO_STRING[i]]) |
|
self.rune_group = Group() |
|
self.rune_group.load_json(data['rune_group']) |
|
self.rune_dsc = data['rune_dsc'] |
|
self.rune_fx_txt = data['rune_fx_txt'] |
|
self.rune_group_tactics = data['rune_group_tactics'] |
|
self.rune_group_role_set = data['rune_group_role_set'] |
|
self.rune_enemy_monster_types = [] |
|
for monster in data['rune_enemy_monster_types']: |
|
self.rune_enemy_monster_types.append(string_to_hash(monster)) |
|
self.rune_groupee_monster_types = [] |
|
for monster in data['rune_groupee_monster_types']: |
|
self.rune_groupee_monster_types.append(monster) |
|
self.rune_helper_monster_types = [] |
|
for monster in data['rune_helper_monster_types']: |
|
self.rune_helper_monster_types.append(monster) |
|
self.rune_not_enemy_monster_types = [] |
|
for monster in data['rune_not_enemy_monster_types']: |
|
self.rune_not_enemy_monster_types.append(string_to_hash(monster)) |
|
self.rune_enemy_gender = [] |
|
for gender in data['rune_enemy_gender']: |
|
self.rune_enemy_gender.append(gender) |
|
self.rune_skill_grant = [] |
|
for grant_data in data['rune_skill_grant']: |
|
grant = SkillGrant() |
|
grant.load_json(grant_data) |
|
self.rune_skill_grant.append(grant) |
|
self.rune_skill_adj = [] |
|
for adjust_data in data['rune_skill_adj']: |
|
adjust = SkillAdjust() |
|
adjust.load_json(adjust_data) |
|
self.rune_skill_adj.append(adjust) |
|
self.rune_attr_adj = [] |
|
for attr_data in data['rune_attr_adj']: |
|
attr = AttributeValue() |
|
attr.load_json(attr_data) |
|
self.rune_attr_adj.append(attr) |
|
self.rune_max_attr_adj = [] |
|
for attr_data in data['rune_max_attr_adj']: |
|
attr = AttributeValue() |
|
attr.load_json(attr_data) |
|
self.rune_max_attr_adj.append(attr) |
|
self.rune_naturalattacks = data['rune_naturalattacks'] |
|
self.rune_enchantment_type = [] |
|
for enchantment in data['rune_enchantment_type']: |
|
self.rune_enchantment_type.append(enchantment) |
|
self.rune_inventory_contents = [] |
|
for content_data in data['rune_inventory_contents']: |
|
content = Inventory() |
|
content.load_json(content_data) |
|
self.rune_inventory_contents.append(content) |
|
self.rune_renderable = data['rune_renderable'] |
|
if self.rune_renderable: |
|
self.rune_scale_factor = data['rune_scale_factor'] |
|
self.rune_skeleton = data['rune_skeleton'] |
|
self.rune_slope_hugger = data['rune_slope_hugger'] |
|
self.rune_can_fly = data['rune_can_fly'] |
|
self.rune_death_effect = data['rune_death_effect'] |
|
self.rune_tombstone_id = data['rune_tombstone_id'] |
|
self.rune_body_parts = [] |
|
for part_data in data['rune_body_parts']: |
|
part = BodyPart() |
|
part.load_json(part_data) |
|
self.rune_body_parts.append(part) |
|
self.rune_hair = data['rune_hair'] |
|
self.rune_beard = data['rune_beard'] |
|
self.rune_natural_power_attack = data['rune_natural_power_attack'] |
|
self.rune_sparse_data = SparseData() |
|
self.rune_sparse_data.load_json(data['rune_sparse_data']) |
|
|
|
def save_json(self): |
|
data = super().save_json() |
|
data['rune_type'] = RUNE_TYPE_TO_STRING[self.rune_type] |
|
data['rune_sub_type'] = hash_to_string(self.rune_sub_type) |
|
data['rune_is_standard_character_creation'] = self.rune_is_standard_character_creation |
|
data['rune_creation_cost'] = self.rune_creation_cost |
|
data['rune_rank'] = self.rune_rank |
|
data['rune_pracs_per_level'] = self.rune_pracs_per_level |
|
data['rune_exp_req_to_level'] = self.rune_exp_req_to_level |
|
data['rune_sex'] = RUNE_SEX_TO_STRING[self.rune_sex] |
|
data['rune_class_icon'] = self.rune_class_icon |
|
data['rune_health'] = self.rune_health |
|
data['rune_mana'] = self.rune_mana |
|
data['rune_stamina'] = self.rune_stamina |
|
data['rune_min_damage'] = self.rune_min_damage |
|
data['rune_max_damage'] = self.rune_max_damage |
|
data['rune_attack'] = self.rune_attack |
|
data['rune_defense'] = self.rune_defense |
|
data['rune_level'] = self.rune_level |
|
data['rune_speed'] = OrderedDict() |
|
for i in range(7): |
|
data['rune_speed'][SPEED_TYPE_TO_STRING[i]] = self.rune_speed[i] |
|
data['rune_group'] = self.rune_group.save_json() |
|
data['rune_dsc'] = self.rune_dsc |
|
data['rune_fx_txt'] = self.rune_fx_txt |
|
data['rune_group_tactics'] = self.rune_group_tactics |
|
data['rune_group_role_set'] = self.rune_group_role_set |
|
data['rune_enemy_monster_types'] = [] |
|
for monster in self.rune_enemy_monster_types: |
|
data['rune_enemy_monster_types'].append(hash_to_string(monster)) |
|
data['rune_groupee_monster_types'] = [] |
|
for monster in self.rune_groupee_monster_types: |
|
data['rune_groupee_monster_types'].append(monster) |
|
data['rune_helper_monster_types'] = [] |
|
for monster in self.rune_helper_monster_types: |
|
data['rune_helper_monster_types'].append(monster) |
|
data['rune_not_enemy_monster_types'] = [] |
|
for monster in self.rune_not_enemy_monster_types: |
|
data['rune_not_enemy_monster_types'].append(hash_to_string(monster)) |
|
data['rune_enemy_gender'] = [] |
|
for gender in self.rune_enemy_gender: |
|
data['rune_enemy_gender'].append(gender) |
|
data['rune_skill_grant'] = [] |
|
for grant in self.rune_skill_grant: |
|
data['rune_skill_grant'].append(grant.save_json()) |
|
data['rune_skill_adj'] = [] |
|
for adjust in self.rune_skill_adj: |
|
data['rune_skill_adj'].append(adjust.save_json()) |
|
data['rune_attr_adj'] = [] |
|
for attr in self.rune_attr_adj: |
|
data['rune_attr_adj'].append(attr.save_json()) |
|
data['rune_max_attr_adj'] = [] |
|
for attr in self.rune_max_attr_adj: |
|
data['rune_max_attr_adj'].append(attr.save_json()) |
|
data['rune_naturalattacks'] = self.rune_naturalattacks |
|
data['rune_enchantment_type'] = [] |
|
for enchantment in self.rune_enchantment_type: |
|
data['rune_enchantment_type'].append(enchantment) |
|
data['rune_inventory_contents'] = [] |
|
for content in self.rune_inventory_contents: |
|
data['rune_inventory_contents'].append(content.save_json()) |
|
data['rune_renderable'] = self.rune_renderable |
|
if self.rune_renderable: |
|
data['rune_scale_factor'] = self.rune_scale_factor |
|
data['rune_skeleton'] = self.rune_skeleton |
|
data['rune_slope_hugger'] = self.rune_slope_hugger |
|
data['rune_can_fly'] = self.rune_can_fly |
|
data['rune_death_effect'] = self.rune_death_effect |
|
data['rune_tombstone_id'] = self.rune_tombstone_id |
|
data['rune_body_parts'] = [] |
|
for part in self.rune_body_parts: |
|
data['rune_body_parts'].append(part.save_json()) |
|
data['rune_hair'] = self.rune_hair |
|
data['rune_beard'] = self.rune_beard |
|
data['rune_natural_power_attack'] = self.rune_natural_power_attack |
|
data['rune_sparse_data'] = self.rune_sparse_data.save_json() |
|
return data
|
|
|