mbEditorPro2.0 release
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from arcane.util import ResStream
|
||||
from .ArcStructureObject import ArcStructureObject
|
||||
|
||||
|
||||
class ArcAssetStructureObject(ArcStructureObject):
|
||||
def load_binary(self, stream: ResStream):
|
||||
super().load_binary(stream)
|
||||
self.asset_structure_template_id = stream.read_qword()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
super().save_binary(stream)
|
||||
stream.write_qword(self.asset_structure_template_id)
|
||||
|
||||
def load_json(self, data):
|
||||
super().load_json(data)
|
||||
self.asset_structure_template_id = data['asset_structure_template_id']
|
||||
|
||||
def save_json(self):
|
||||
data = super().save_json()
|
||||
data['asset_structure_template_id'] = self.asset_structure_template_id
|
||||
return data
|
||||
@@ -0,0 +1,386 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.util import ResStream
|
||||
|
||||
|
||||
class RankInfo:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.rank_hirelings = stream.read_dword()
|
||||
self.rank_shrines = stream.read_dword()
|
||||
self.rank_spires = stream.read_dword()
|
||||
self.rank_barracks = stream.read_dword()
|
||||
self.rank_rank = stream.read_dword()
|
||||
self.rank_health = stream.read_dword()
|
||||
self.rank_automatic = stream.read_bool()
|
||||
self.rank_energy_k1 = stream.read_float()
|
||||
self.rank_energy_k2 = stream.read_float()
|
||||
self.rank_level_val = stream.read_float()
|
||||
num_builiding_ids = stream.read_dword()
|
||||
self.rank_building_id = [
|
||||
[
|
||||
stream.read_dword(),
|
||||
stream.read_qword(),
|
||||
] for _ in range(num_builiding_ids)
|
||||
]
|
||||
self.rank_formula = stream.read_dword()
|
||||
num_placement_limits = stream.read_dword()
|
||||
self.rank_placement_limit = [
|
||||
[
|
||||
stream.read_dword(),
|
||||
stream.read_dword(),
|
||||
] for _ in range(num_placement_limits)
|
||||
]
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.rank_hirelings)
|
||||
stream.write_dword(self.rank_shrines)
|
||||
stream.write_dword(self.rank_spires)
|
||||
stream.write_dword(self.rank_barracks)
|
||||
stream.write_dword(self.rank_rank)
|
||||
stream.write_dword(self.rank_health)
|
||||
stream.write_bool(self.rank_automatic)
|
||||
stream.write_float(self.rank_energy_k1)
|
||||
stream.write_float(self.rank_energy_k2)
|
||||
stream.write_float(self.rank_level_val)
|
||||
stream.write_dword(len(self.rank_building_id))
|
||||
for building in self.rank_building_id:
|
||||
stream.write_dword(building[0])
|
||||
stream.write_qword(building[1])
|
||||
stream.write_dword(self.rank_formula)
|
||||
stream.write_dword(len(self.rank_placement_limit))
|
||||
for placement in self.rank_placement_limit:
|
||||
stream.write_dword(placement[0])
|
||||
stream.write_dword(placement[1])
|
||||
|
||||
def load_json(self, data):
|
||||
self.rank_hirelings = data['rank_hirelings']
|
||||
self.rank_shrines = data['rank_shrines']
|
||||
self.rank_spires = data['rank_spires']
|
||||
self.rank_barracks = data['rank_barracks']
|
||||
self.rank_rank = data['rank_rank']
|
||||
self.rank_health = data['rank_health']
|
||||
self.rank_automatic = data['rank_automatic']
|
||||
self.rank_energy_k1 = data['rank_energy_k1']
|
||||
self.rank_energy_k2 = data['rank_energy_k2']
|
||||
self.rank_level_val = data['rank_level_val']
|
||||
self.rank_building_id = data['rank_building_id']
|
||||
self.rank_formula = data['rank_formula']
|
||||
self.rank_placement_limit = data['rank_placement_limit']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['rank_hirelings'] = self.rank_hirelings
|
||||
data['rank_shrines'] = self.rank_shrines
|
||||
data['rank_spires'] = self.rank_spires
|
||||
data['rank_barracks'] = self.rank_barracks
|
||||
data['rank_rank'] = self.rank_rank
|
||||
data['rank_health'] = self.rank_health
|
||||
data['rank_automatic'] = self.rank_automatic
|
||||
data['rank_energy_k1'] = self.rank_energy_k1
|
||||
data['rank_energy_k2'] = self.rank_energy_k2
|
||||
data['rank_level_val'] = self.rank_level_val
|
||||
data['rank_building_id'] = self.rank_building_id
|
||||
data['rank_formula'] = self.rank_formula
|
||||
data['rank_placement_limit'] = self.rank_placement_limit
|
||||
return data
|
||||
|
||||
|
||||
class ArcCityAssetTemplate():
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.template_max_ranks = stream.read_dword()
|
||||
self.template_start_rank = stream.read_dword()
|
||||
self.template_asset_type = stream.read_dword()
|
||||
self.template_trade_icon = stream.read_dword()
|
||||
self.template_landmark = stream.read_dword()
|
||||
self.template_is_maintenance = stream.read_bool()
|
||||
self.template_has_keys = stream.read_bool()
|
||||
self.template_use_hardpoints = stream.read_bool()
|
||||
self.template_is_fort_asset = stream.read_bool()
|
||||
self.template_is_building_of_war = stream.read_bool()
|
||||
self.template_bow_can_place_on_grid = stream.read_bool()
|
||||
self.template_requires_nation_tree_slot = stream.read_bool()
|
||||
self.template_requires_guild_tree_slot = stream.read_bool()
|
||||
self.template_use_fort_grid = stream.read_bool()
|
||||
self.template_is_fort_start = stream.read_bool()
|
||||
self.template_is_cap_asset = stream.read_bool()
|
||||
self.template_zone_no_build = [
|
||||
stream.read_float(),
|
||||
stream.read_float(),
|
||||
]
|
||||
self.template_zone_influence = [
|
||||
stream.read_float(),
|
||||
stream.read_float(),
|
||||
]
|
||||
self.template_eject_loc = stream.read_tuple()
|
||||
self.template_npc_load = stream.read_tuple()
|
||||
self.template_fort_grid_offset = stream.read_tuple()
|
||||
self.template_power_action_id = stream.read_dword()
|
||||
self.template_zone_flag = stream.read_dword()
|
||||
self.template_spire_event_rule = stream.read_dword()
|
||||
self.template_maintenance_set = stream.read_dword()
|
||||
self.template_damage_set = stream.read_dword()
|
||||
self.template_energy_set = stream.read_dword()
|
||||
self.template_use_trigger = stream.read_string()
|
||||
|
||||
self.template_unknown_check1 = stream.read_bool()
|
||||
if self.template_unknown_check1:
|
||||
pass
|
||||
self.template_loot_trigger = stream.read_string()
|
||||
|
||||
self.template_unknown_check2 = stream.read_bool()
|
||||
if self.template_unknown_check2:
|
||||
pass
|
||||
|
||||
self.has_embedded_template = stream.read_bool()
|
||||
if self.has_embedded_template:
|
||||
self.template_embed_template = ArcCityAssetTemplate()
|
||||
self.template_embed_template.load_binary(stream)
|
||||
num_creators = stream.read_dword()
|
||||
self.template_creator = [
|
||||
stream.read_dword() for _ in range(num_creators)
|
||||
]
|
||||
num_terrains = stream.read_dword()
|
||||
self.template_terrain = [
|
||||
stream.read_dword() for _ in range(num_terrains)
|
||||
]
|
||||
num_valid_npc_types = stream.read_dword()
|
||||
self.template_valid_npc_type = [
|
||||
stream.read_dword() for _ in range(num_valid_npc_types)
|
||||
]
|
||||
num_valid_npc_cat = stream.read_dword()
|
||||
self.template_valid_npc_cat = [
|
||||
stream.read_dword() for _ in range(num_valid_npc_cat)
|
||||
]
|
||||
num_rank_info = stream.read_dword()
|
||||
self.template_rank_info = [RankInfo() for _ in range(num_rank_info)]
|
||||
for rank_info in self.template_rank_info:
|
||||
rank_info.load_binary(stream)
|
||||
num_cap_info = stream.read_dword()
|
||||
self.template_cap_info = [
|
||||
[
|
||||
stream.read_dword(),
|
||||
stream.read_dword(),
|
||||
stream.read_qword(),
|
||||
] for _ in range(num_cap_info)
|
||||
]
|
||||
num_event_rules = stream.read_dword()
|
||||
self.template_event_rules = [
|
||||
[
|
||||
stream.read_dword(),
|
||||
stream.read_dword(),
|
||||
] for _ in range(num_event_rules)
|
||||
]
|
||||
num_archs = stream.read_dword()
|
||||
self.template_architecture = [
|
||||
stream.read_string() for _ in range(num_archs)
|
||||
]
|
||||
self.template_offering_type = stream.read_string()
|
||||
self.template_placement_type = stream.read_dword()
|
||||
num_offering_adjusts = stream.read_dword()
|
||||
self.template_offering_adjustment = [
|
||||
[
|
||||
stream.read_dword(),
|
||||
stream.read_float(),
|
||||
] for _ in range(num_offering_adjusts)
|
||||
]
|
||||
num_resource_limit = stream.read_dword()
|
||||
self.template_resource_limit = [
|
||||
[
|
||||
stream.read_dword(),
|
||||
stream.read_dword(),
|
||||
stream.read_dword(),
|
||||
] for _ in range(num_resource_limit)
|
||||
]
|
||||
self.template_unknown = stream.read_dword()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.template_max_ranks)
|
||||
stream.write_dword(self.template_start_rank)
|
||||
stream.write_dword(self.template_asset_type)
|
||||
stream.write_dword(self.template_trade_icon)
|
||||
stream.write_dword(self.template_landmark)
|
||||
stream.write_bool(self.template_is_maintenance)
|
||||
stream.write_bool(self.template_has_keys)
|
||||
stream.write_bool(self.template_use_hardpoints)
|
||||
stream.write_bool(self.template_is_fort_asset)
|
||||
stream.write_bool(self.template_is_building_of_war)
|
||||
stream.write_bool(self.template_bow_can_place_on_grid)
|
||||
stream.write_bool(self.template_requires_nation_tree_slot)
|
||||
stream.write_bool(self.template_requires_guild_tree_slot)
|
||||
stream.write_bool(self.template_use_fort_grid)
|
||||
stream.write_bool(self.template_is_fort_start)
|
||||
stream.write_bool(self.template_is_cap_asset)
|
||||
stream.write_float(self.template_zone_no_build[0])
|
||||
stream.write_float(self.template_zone_no_build[1])
|
||||
stream.write_float(self.template_zone_influence[0])
|
||||
stream.write_float(self.template_zone_influence[1])
|
||||
stream.write_tuple(self.template_eject_loc)
|
||||
stream.write_tuple(self.template_npc_load)
|
||||
stream.write_tuple(self.template_fort_grid_offset)
|
||||
stream.write_dword(self.template_power_action_id)
|
||||
stream.write_dword(self.template_zone_flag)
|
||||
stream.write_dword(self.template_spire_event_rule)
|
||||
stream.write_dword(self.template_maintenance_set)
|
||||
stream.write_dword(self.template_damage_set)
|
||||
stream.write_dword(self.template_energy_set)
|
||||
stream.write_string(self.template_use_trigger)
|
||||
stream.write_bool(self.template_unknown_check1)
|
||||
stream.write_string(self.template_loot_trigger)
|
||||
stream.write_bool(self.template_unknown_check2)
|
||||
stream.write_bool(self.has_embedded_template)
|
||||
if self.has_embedded_template:
|
||||
self.template_embed_template.save_binary(stream)
|
||||
stream.write_dword(len(self.template_creator))
|
||||
for creator in self.template_creator:
|
||||
stream.write_dword(creator)
|
||||
stream.write_dword(len(self.template_terrain))
|
||||
for terrain in self.template_terrain:
|
||||
stream.write_dword(terrain)
|
||||
stream.write_dword(len(self.template_valid_npc_type))
|
||||
for npc_type in self.template_valid_npc_type:
|
||||
stream.write_dword(npc_type)
|
||||
stream.write_dword(len(self.template_valid_npc_cat))
|
||||
for npc_cat in self.template_valid_npc_cat:
|
||||
stream.write_dword(npc_cat)
|
||||
stream.write_dword(len(self.template_rank_info))
|
||||
for rank_info in self.template_rank_info:
|
||||
rank_info.save_binary(stream)
|
||||
stream.write_dword(len(self.template_cap_info))
|
||||
for cap in self.template_cap_info:
|
||||
stream.write_dword(cap[0])
|
||||
stream.write_dword(cap[1])
|
||||
stream.write_qword(cap[2])
|
||||
stream.write_dword(len(self.template_event_rules))
|
||||
for event in self.template_event_rules:
|
||||
stream.write_dword(event[0])
|
||||
stream.write_dword(event[1])
|
||||
stream.write_dword(len(self.template_architecture))
|
||||
for arch in self.template_architecture:
|
||||
stream.write_string(arch)
|
||||
stream.write_string(self.template_offering_type)
|
||||
stream.write_dword(self.template_placement_type)
|
||||
stream.write_dword(len(self.template_offering_adjustment))
|
||||
for adjust in self.template_offering_adjustment:
|
||||
stream.write_dword(adjust[0])
|
||||
stream.write_float(adjust[1])
|
||||
stream.write_dword(len(self.template_resource_limit))
|
||||
for resource in self.template_resource_limit:
|
||||
stream.write_dword(resource[0])
|
||||
stream.write_dword(resource[1])
|
||||
stream.write_dword(resource[2])
|
||||
stream.write_dword(self.template_unknown)
|
||||
|
||||
def load_json(self, data):
|
||||
self.template_max_ranks = data['template_max_ranks']
|
||||
self.template_start_rank = data['template_start_rank']
|
||||
self.template_asset_type = data['template_asset_type']
|
||||
self.template_trade_icon = data['template_trade_icon']
|
||||
self.template_landmark = data['template_landmark']
|
||||
self.template_is_maintenance = data['template_is_maintenance']
|
||||
self.template_has_keys = data['template_has_keys']
|
||||
self.template_use_hardpoints = data['template_use_hardpoints']
|
||||
self.template_is_fort_asset = data['template_is_fort_asset']
|
||||
self.template_is_building_of_war = data['template_is_building_of_war']
|
||||
self.template_bow_can_place_on_grid = data['template_bow_can_place_on_grid']
|
||||
self.template_requires_nation_tree_slot = data['template_requires_nation_tree_slot']
|
||||
self.template_requires_guild_tree_slot = data['template_requires_guild_tree_slot']
|
||||
self.template_use_fort_grid = data['template_use_fort_grid']
|
||||
self.template_is_fort_start = data['template_is_fort_start']
|
||||
self.template_is_cap_asset = data['template_is_cap_asset']
|
||||
self.template_zone_no_build = data['template_zone_no_build']
|
||||
self.template_zone_influence = data['template_zone_influence']
|
||||
self.template_eject_loc = data['template_eject_loc']
|
||||
self.template_npc_load = data['template_npc_load']
|
||||
self.template_fort_grid_offset = data['template_fort_grid_offset']
|
||||
self.template_power_action_id = data['template_power_action_id']
|
||||
self.template_zone_flag = data['template_zone_flag']
|
||||
self.template_spire_event_rule = data['template_spire_event_rule']
|
||||
self.template_maintenance_set = data['template_maintenance_set']
|
||||
self.template_damage_set = data['template_damage_set']
|
||||
self.template_energy_set = data['template_energy_set']
|
||||
self.template_use_trigger = data['template_use_trigger']
|
||||
self.template_unknown_check1 = data['template_unknown_check1']
|
||||
self.template_loot_trigger = data['template_loot_trigger']
|
||||
self.template_unknown_check2 = data['template_unknown_check2']
|
||||
self.has_embedded_template = data['has_embedded_template']
|
||||
if self.has_embedded_template:
|
||||
self.template_embed_template = ArcCityAssetTemplate()
|
||||
self.template_embed_template.load_json(data['template_embed_template'])
|
||||
self.template_creator = data['template_creator']
|
||||
self.template_terrain = data['template_terrain']
|
||||
self.template_valid_npc_type = data['template_valid_npc_type']
|
||||
self.template_valid_npc_cat = data['template_valid_npc_cat']
|
||||
self.template_rank_info = []
|
||||
for rank_info_data in data['template_rank_info']:
|
||||
rank_info = RankInfo()
|
||||
rank_info.load_json(rank_info_data)
|
||||
self.template_rank_info.append(rank_info)
|
||||
self.template_cap_info = data['template_cap_info']
|
||||
self.template_event_rules = data['template_event_rules']
|
||||
self.template_architecture = data['template_architecture']
|
||||
self.template_offering_type = data['template_offering_type']
|
||||
self.template_placement_type = data['template_placement_type']
|
||||
self.template_offering_adjustment = data['template_offering_adjustment']
|
||||
self.template_resource_limit = data['template_resource_limit']
|
||||
self.template_unknown = data['template_unknown']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['template_max_ranks'] = self.template_max_ranks
|
||||
data['template_start_rank'] = self.template_start_rank
|
||||
data['template_asset_type'] = self.template_asset_type
|
||||
data['template_trade_icon'] = self.template_trade_icon
|
||||
data['template_landmark'] = self.template_landmark
|
||||
data['template_is_maintenance'] = self.template_is_maintenance
|
||||
data['template_has_keys'] = self.template_has_keys
|
||||
data['template_use_hardpoints'] = self.template_use_hardpoints
|
||||
data['template_is_fort_asset'] = self.template_is_fort_asset
|
||||
data['template_is_building_of_war'] = self.template_is_building_of_war
|
||||
data['template_bow_can_place_on_grid'] = self.template_bow_can_place_on_grid
|
||||
data['template_requires_nation_tree_slot'] = self.template_requires_nation_tree_slot
|
||||
data['template_requires_guild_tree_slot'] = self.template_requires_guild_tree_slot
|
||||
data['template_use_fort_grid'] = self.template_use_fort_grid
|
||||
data['template_is_fort_start'] = self.template_is_fort_start
|
||||
data['template_is_cap_asset'] = self.template_is_cap_asset
|
||||
data['template_zone_no_build'] = self.template_zone_no_build
|
||||
data['template_zone_influence'] = self.template_zone_influence
|
||||
data['template_eject_loc'] = self.template_eject_loc
|
||||
data['template_npc_load'] = self.template_npc_load
|
||||
data['template_fort_grid_offset'] = self.template_fort_grid_offset
|
||||
data['template_power_action_id'] = self.template_power_action_id
|
||||
data['template_zone_flag'] = self.template_zone_flag
|
||||
data['template_spire_event_rule'] = self.template_spire_event_rule
|
||||
data['template_maintenance_set'] = self.template_maintenance_set
|
||||
data['template_damage_set'] = self.template_damage_set
|
||||
data['template_energy_set'] = self.template_energy_set
|
||||
data['template_use_trigger'] = self.template_use_trigger
|
||||
data['template_unknown_check1'] = self.template_unknown_check1
|
||||
data['template_loot_trigger'] = self.template_loot_trigger
|
||||
data['template_unknown_check2'] = self.template_unknown_check2
|
||||
data['has_embedded_template'] = self.has_embedded_template
|
||||
if self.has_embedded_template:
|
||||
data['template_embed_template'] = self.template_embed_template.save_json()
|
||||
data['template_creator'] = self.template_creator
|
||||
data['template_terrain'] = self.template_terrain
|
||||
data['template_valid_npc_type'] = self.template_valid_npc_type
|
||||
data['template_valid_npc_cat'] = self.template_valid_npc_cat
|
||||
data['template_rank_info'] = []
|
||||
for rank_info in self.template_rank_info:
|
||||
data['template_rank_info'].append(rank_info.save_json())
|
||||
data['template_cap_info'] = self.template_cap_info
|
||||
data['template_event_rules'] = self.template_event_rules
|
||||
data['template_architecture'] = self.template_architecture
|
||||
data['template_offering_type'] = self.template_offering_type
|
||||
data['template_placement_type'] = self.template_placement_type
|
||||
data['template_offering_adjustment'] = self.template_offering_adjustment
|
||||
data['template_resource_limit'] = self.template_resource_limit
|
||||
data['template_unknown'] = self.template_unknown
|
||||
return data
|
||||
@@ -0,0 +1,68 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.enums.arc_combat import *
|
||||
from arcane.util import ResStream
|
||||
from .ArcObj import ArcObj
|
||||
|
||||
|
||||
class ArcCombatObj(ArcObj):
|
||||
def load_binary(self, stream: ResStream):
|
||||
super().load_binary(stream)
|
||||
self.combat_health_current = stream.read_float()
|
||||
self.combat_health_full = stream.read_float()
|
||||
self.combat_attack_resist = [
|
||||
stream.read_float() for _ in range(0x10)
|
||||
]
|
||||
num_powers = stream.read_dword()
|
||||
self.combat_powers = [
|
||||
[
|
||||
stream.read_dword(),
|
||||
stream.read_dword(),
|
||||
] for _ in range(num_powers)
|
||||
]
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
super().save_binary(stream)
|
||||
stream.write_float(self.combat_health_current)
|
||||
stream.write_float(self.combat_health_full)
|
||||
for i in range(0x10):
|
||||
stream.write_float(self.combat_attack_resist[i])
|
||||
stream.write_dword(len(self.combat_powers))
|
||||
for power in self.combat_powers:
|
||||
stream.write_dword(power[0])
|
||||
stream.write_dword(power[1])
|
||||
|
||||
def load_json(self, data):
|
||||
super().load_json(data)
|
||||
self.combat_health_current = data['combat_health_current']
|
||||
self.combat_health_full = data['combat_health_full']
|
||||
self.combat_attack_resist = []
|
||||
for i in range(0x10):
|
||||
self.combat_attack_resist.append(data['combat_attack_resist'][
|
||||
ATTACK_RESIST_TO_STRING[i]
|
||||
])
|
||||
self.combat_powers = data['combat_powers']
|
||||
|
||||
def save_json(self):
|
||||
data = super().save_json()
|
||||
data['combat_health_current'] = self.combat_health_current
|
||||
data['combat_health_full'] = self.combat_health_full
|
||||
data['combat_attack_resist'] = OrderedDict()
|
||||
for i in range(0x10):
|
||||
data['combat_attack_resist'][
|
||||
ATTACK_RESIST_TO_STRING[i]
|
||||
] = self.combat_attack_resist[i]
|
||||
data['combat_powers'] = self.combat_powers
|
||||
return data
|
||||
|
||||
|
||||
class ArcCharacter(ArcCombatObj):
|
||||
pass
|
||||
@@ -0,0 +1,69 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from arcane.util import ResStream
|
||||
from .ArcItem import ArcItem
|
||||
from .common.Inventory import Inventory
|
||||
|
||||
|
||||
class ArcContainerObject(ArcItem):
|
||||
def load_binary(self, stream: ResStream):
|
||||
super().load_binary(stream)
|
||||
self.container_open = stream.read_dword()
|
||||
self.container_locked = stream.read_dword()
|
||||
self.container_locked_rank = stream.read_dword()
|
||||
self.container_barred = stream.read_dword()
|
||||
self.container_barred_rank = stream.read_dword()
|
||||
self.container_trapped = stream.read_dword()
|
||||
self.container_trappe_rank = stream.read_dword()
|
||||
num_contents = stream.read_dword()
|
||||
self.container_inventory_contents = [Inventory() for _ in range(num_contents)]
|
||||
for content in self.container_inventory_contents:
|
||||
content.load_binary(stream)
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
super().save_binary(stream)
|
||||
stream.read_dword(self.container_open)
|
||||
stream.read_dword(self.container_locked)
|
||||
stream.read_dword(self.container_locked_rank)
|
||||
stream.read_dword(self.container_barred)
|
||||
stream.read_dword(self.container_barred_rank)
|
||||
stream.read_dword(self.container_trapped)
|
||||
stream.read_dword(self.container_trappe_rank)
|
||||
stream.read_dword(len(self.container_inventory_contents))
|
||||
for content in self.container_inventory_contents:
|
||||
content.save_binary(stream)
|
||||
|
||||
def load_json(self, data):
|
||||
super().load_json()
|
||||
self.container_open = data['container_open']
|
||||
self.container_locked = data['container_locked']
|
||||
self.container_locked_rank = data['container_locked_rank']
|
||||
self.container_barred = data['container_barred']
|
||||
self.container_barred_rank = data['container_barred_rank']
|
||||
self.container_trapped = data['container_trapped']
|
||||
self.container_trappe_rank = data['container_trappe_rank']
|
||||
self.container_inventory_contents = []
|
||||
for content_data in data['container_inventory_contents']:
|
||||
content = Inventory()
|
||||
content.load_json(content_data)
|
||||
self.container_inventory_contents.append(content)
|
||||
|
||||
def save_json(self):
|
||||
data = super().save_json()
|
||||
data['container_open'] = self.container_open
|
||||
data['container_locked'] = self.container_locked
|
||||
data['container_locked_rank'] = self.container_locked_rank
|
||||
data['container_barred'] = self.container_barred
|
||||
data['container_barred_rank'] = self.container_barred_rank
|
||||
data['container_trapped'] = self.container_trapped
|
||||
data['container_trappe_rank'] = self.container_trappe_rank
|
||||
data['container_inventory_contents'] = []
|
||||
for content in self.container_inventory_contents:
|
||||
data['container_inventory_contents'].append(content.save_json())
|
||||
return data
|
||||
@@ -0,0 +1,83 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from arcane.util import ResStream
|
||||
from .ArcItem import ArcItem
|
||||
|
||||
|
||||
class ArcDeed(ArcItem):
|
||||
def load_binary(self, stream: ResStream):
|
||||
super().load_binary(stream)
|
||||
self.deed_type = stream.read_dword()
|
||||
self.deed_furniture_id = stream.read_qword()
|
||||
self.deed_target_id = stream.read_qword()
|
||||
self.deed_employment = stream.read_dword()
|
||||
self.deed_start_rank = stream.read_dword()
|
||||
self.deed_name_lookup = stream.read_dword()
|
||||
self.deed_indoors = stream.read_bool()
|
||||
self.deed_is_fortress = stream.read_bool()
|
||||
self.deed_namelookup_val = stream.read_float()
|
||||
self.deed_custom_city = stream.read_bool()
|
||||
if self.deed_custom_city:
|
||||
set_length = stream.read_dword()
|
||||
self.deed_custom_city_set = [
|
||||
stream.read_dword() for _ in range(set_length)
|
||||
]
|
||||
|
||||
self.deed_structure_id = stream.read_qword()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
super().save_binary(stream)
|
||||
stream.write_dword(self.deed_type)
|
||||
stream.write_qword(self.deed_furniture_id)
|
||||
stream.write_qword(self.deed_target_id)
|
||||
stream.write_dword(self.deed_employment)
|
||||
stream.write_dword(self.deed_start_rank)
|
||||
stream.write_dword(self.deed_name_lookup)
|
||||
stream.write_bool(self.deed_indoors)
|
||||
stream.write_bool(self.deed_is_fortress)
|
||||
stream.write_float(self.deed_namelookup_val)
|
||||
stream.write_bool(self.deed_custom_city)
|
||||
if self.deed_custom_city:
|
||||
stream.write_dword(len(self.deed_custom_city_set))
|
||||
for city in self.deed_custom_city_set:
|
||||
stream.write_dword(city)
|
||||
stream.write_qword(self.deed_structure_id)
|
||||
|
||||
def load_json(self, data):
|
||||
super().load_json(data)
|
||||
self.deed_type = data['deed_type']
|
||||
self.deed_furniture_id = data['deed_furniture_id']
|
||||
self.deed_target_id = data['deed_target_id']
|
||||
self.deed_employment = data['deed_employment']
|
||||
self.deed_start_rank = data['deed_start_rank']
|
||||
self.deed_name_lookup = data['deed_name_lookup']
|
||||
self.deed_indoors = data['deed_indoors']
|
||||
self.deed_is_fortress = data['deed_is_fortress']
|
||||
self.deed_namelookup_val = data['deed_namelookup_val']
|
||||
self.deed_custom_city = data['deed_custom_city']
|
||||
if self.deed_custom_city:
|
||||
self.deed_custom_city_set = data['deed_custom_city_set']
|
||||
self.deed_structure_id = data['deed_structure_id']
|
||||
|
||||
def save_json(self):
|
||||
data = super().save_json()
|
||||
data['deed_type'] = self.deed_type
|
||||
data['deed_furniture_id'] = self.deed_furniture_id
|
||||
data['deed_target_id'] = self.deed_target_id
|
||||
data['deed_employment'] = self.deed_employment
|
||||
data['deed_start_rank'] = self.deed_start_rank
|
||||
data['deed_name_lookup'] = self.deed_name_lookup
|
||||
data['deed_indoors'] = self.deed_indoors
|
||||
data['deed_is_fortress'] = self.deed_is_fortress
|
||||
data['deed_namelookup_val'] = self.deed_namelookup_val
|
||||
data['deed_custom_city'] = self.deed_custom_city
|
||||
if self.deed_custom_city:
|
||||
data['deed_custom_city_set'] = self.deed_custom_city_set
|
||||
data['deed_structure_id'] = self.deed_structure_id
|
||||
return data
|
||||
@@ -0,0 +1,88 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.enums.arc_door import *
|
||||
from arcane.util import ResStream
|
||||
|
||||
|
||||
class ArcDoorObject():
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.door_id = stream.read_qword()
|
||||
self.door_type = stream.read_dword()
|
||||
self.door_movement_axis = stream.read_dword()
|
||||
self.door_swing_direction = stream.read_dword()
|
||||
self.door_min_time_to_stay_open = stream.read_float()
|
||||
self.door_max_time_to_stay_open = stream.read_float()
|
||||
self.door_swing_time = stream.read_float()
|
||||
self.door_swing = stream.read_float()
|
||||
self.door_slide_distance = stream.read_float()
|
||||
self.door_slide_direction = stream.read_tuple()
|
||||
self.door_slide_start = stream.read_tuple()
|
||||
self.door_slide_end = stream.read_tuple()
|
||||
self.door_locked = stream.read_dword()
|
||||
self.door_linked_to = stream.read_qword()
|
||||
self.door_key = stream.read_qword()
|
||||
self.door_sound_event = stream.read_qword()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_qword(self.door_id)
|
||||
stream.write_dword(self.door_type)
|
||||
stream.write_dword(self.door_movement_axis)
|
||||
stream.write_dword(self.door_swing_direction)
|
||||
stream.write_float(self.door_min_time_to_stay_open)
|
||||
stream.write_float(self.door_max_time_to_stay_open)
|
||||
stream.write_float(self.door_swing_time)
|
||||
stream.write_float(self.door_swing)
|
||||
stream.write_float(self.door_slide_distance)
|
||||
stream.write_tuple(self.door_slide_direction)
|
||||
stream.write_tuple(self.door_slide_start)
|
||||
stream.write_tuple(self.door_slide_end)
|
||||
stream.write_dword(self.door_locked)
|
||||
stream.write_qword(self.door_linked_to)
|
||||
stream.write_qword(self.door_key)
|
||||
stream.write_qword(self.door_sound_event)
|
||||
|
||||
def load_json(self, data):
|
||||
self.door_id = data['door_id']
|
||||
self.door_type = STRING_TO_DOOR_TYPE[data['door_type']]
|
||||
self.door_movement_axis = STRING_TO_DOOR_MOVEMENT_AXIS[data['door_movement_axis']]
|
||||
self.door_swing_direction = STRING_TO_DOOR_SWING_DIRECTION[data['door_swing_direction']]
|
||||
self.door_min_time_to_stay_open = data['door_min_time_to_stay_open']
|
||||
self.door_max_time_to_stay_open = data['door_max_time_to_stay_open']
|
||||
self.door_swing_time = data['door_swing_time']
|
||||
self.door_swing = data['door_swing']
|
||||
self.door_slide_distance = data['door_slide_distance']
|
||||
self.door_slide_direction = data['door_slide_direction']
|
||||
self.door_slide_start = data['door_slide_start']
|
||||
self.door_slide_end = data['door_slide_end']
|
||||
self.door_locked = data['door_locked']
|
||||
self.door_linked_to = data['door_linked_to']
|
||||
self.door_key = data['door_key']
|
||||
self.door_sound_event = data['door_sound_event']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['door_id'] = self.door_id
|
||||
data['door_type'] = DOOR_TYPE_TO_STRING[self.door_type]
|
||||
data['door_movement_axis'] = DOOR_MOVEMENT_AXIS_TO_STRING[self.door_movement_axis]
|
||||
data['door_swing_direction'] = DOOR_SWING_DIRECTION_TO_STRING[self.door_swing_direction]
|
||||
data['door_min_time_to_stay_open'] = self.door_min_time_to_stay_open
|
||||
data['door_max_time_to_stay_open'] = self.door_max_time_to_stay_open
|
||||
data['door_swing_time'] = self.door_swing_time
|
||||
data['door_swing'] = self.door_swing
|
||||
data['door_slide_distance'] = self.door_slide_distance
|
||||
data['door_slide_direction'] = self.door_slide_direction
|
||||
data['door_slide_start'] = self.door_slide_start
|
||||
data['door_slide_end'] = self.door_slide_end
|
||||
data['door_locked'] = self.door_locked
|
||||
data['door_linked_to'] = self.door_linked_to
|
||||
data['door_key'] = self.door_key
|
||||
data['door_sound_event'] = self.door_sound_event
|
||||
return data
|
||||
@@ -0,0 +1,43 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from arcane.util.ResStream import ResStream
|
||||
from .ArcStructureObject import ArcStructureObject
|
||||
|
||||
|
||||
class ArcDungeonUnitObject(ArcStructureObject):
|
||||
def load_binary(self, stream: ResStream):
|
||||
super().load_binary(stream)
|
||||
num_connectables = stream.read_dword()
|
||||
self.dungeon_connectable_edges = [
|
||||
stream.read_dword() for _ in range(num_connectables)
|
||||
]
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
super().save_binary(stream)
|
||||
stream.write_dword(len(self.dungeon_connectable_edges))
|
||||
for edge in self.dungeon_connectable_edges:
|
||||
stream.write_dword(edge)
|
||||
|
||||
def load_json(self, data):
|
||||
super().load_json(data)
|
||||
self.dungeon_connectable_edges = data['dungeon_connectable_edges']
|
||||
return data
|
||||
|
||||
def save_json(self):
|
||||
data = super().save_json()
|
||||
data['dungeon_connectable_edges'] = self.dungeon_connectable_edges
|
||||
return data
|
||||
|
||||
|
||||
class ArcDungeonExitObject(ArcDungeonUnitObject):
|
||||
pass
|
||||
|
||||
|
||||
class ArcDungeonStairObject(ArcDungeonUnitObject):
|
||||
pass
|
||||
@@ -0,0 +1,517 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.enums.arc_item import *
|
||||
from arcane.enums.hashes import hash_to_string, string_to_hash
|
||||
from arcane.util import ResStream
|
||||
from .ArcCombatObj import ArcCombatObj
|
||||
from .common.Arcane import AttributeValue, SkillLevel, PowerGrant, PowerAction, ResourceInfo
|
||||
from .common.Class import ClassRequired
|
||||
from .common.Discipline import DiscRequired
|
||||
from .common.Race import RaceRequired
|
||||
|
||||
|
||||
class Damage:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.damage_type = stream.read_dword()
|
||||
self.damage_min = stream.read_dword()
|
||||
self.damage_max = stream.read_dword()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.damage_type)
|
||||
stream.write_dword(self.damage_min)
|
||||
stream.write_dword(self.damage_max)
|
||||
|
||||
def load_json(self, data):
|
||||
self.damage_type = STRING_TO_DAMAGE[data['damage_type']]
|
||||
self.damage_min = data['damage_min']
|
||||
self.damage_max = data['damage_max']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['damage_type'] = DAMAGE_TO_STRING[self.damage_type]
|
||||
data['damage_min'] = self.damage_min
|
||||
data['damage_max'] = self.damage_max
|
||||
return data
|
||||
|
||||
|
||||
class Offerings:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.offering_type = stream.read_string()
|
||||
self.offering_value = stream.read_dword()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_string(self.offering_type)
|
||||
stream.write_dword(self.offering_value)
|
||||
|
||||
def load_json(self, data):
|
||||
self.offering_type = data['offering_type']
|
||||
self.offering_value = data['offering_value']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['offering_type'] = self.offering_type
|
||||
data['offering_value'] = self.offering_value
|
||||
return data
|
||||
|
||||
|
||||
class Weapon:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.weapon_wepspeed = stream.read_float()
|
||||
self.weapon_max_range = stream.read_float()
|
||||
self.weapon_projectile_id = stream.read_qword()
|
||||
self.weapon_projectile_speed = stream.read_float()
|
||||
self.weapon_combat_idle_anim = stream.read_dword()
|
||||
num_damages = stream.read_dword()
|
||||
self.weapon_damage = [Damage() for _ in range(num_damages)]
|
||||
for damage in self.weapon_damage:
|
||||
damage.load_binary(stream)
|
||||
num_right_anims = stream.read_dword()
|
||||
self.weapon_attack_anim_right = [
|
||||
[
|
||||
stream.read_dword(),
|
||||
stream.read_dword(),
|
||||
] for _ in range(num_right_anims)
|
||||
]
|
||||
num_left_anims = stream.read_dword()
|
||||
self.weapon_attack_anim_left = [
|
||||
[
|
||||
stream.read_dword(),
|
||||
stream.read_dword(),
|
||||
] for _ in range(num_left_anims)
|
||||
]
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_float(self.weapon_wepspeed)
|
||||
stream.write_float(self.weapon_max_range)
|
||||
stream.write_qword(self.weapon_projectile_id)
|
||||
stream.write_float(self.weapon_projectile_speed)
|
||||
stream.write_dword(self.weapon_combat_idle_anim)
|
||||
stream.write_dword(len(self.weapon_damage))
|
||||
for damage in self.weapon_damage:
|
||||
damage.save_binary(stream)
|
||||
stream.write_dword(len(self.weapon_attack_anim_right))
|
||||
for anim in self.weapon_attack_anim_right:
|
||||
stream.write_dword(anim[0])
|
||||
stream.write_dword(anim[1])
|
||||
stream.write_dword(len(self.weapon_attack_anim_left))
|
||||
for anim in self.weapon_attack_anim_left:
|
||||
stream.write_dword(anim[0])
|
||||
stream.write_dword(anim[1])
|
||||
|
||||
def load_json(self, data):
|
||||
self.weapon_wepspeed = data['weapon_wepspeed']
|
||||
self.weapon_max_range = data['weapon_max_range']
|
||||
self.weapon_projectile_id = data['weapon_projectile_id']
|
||||
self.weapon_projectile_speed = data['weapon_projectile_speed']
|
||||
self.weapon_combat_idle_anim = data['weapon_combat_idle_anim']
|
||||
self.weapon_damage = []
|
||||
for damage_data in data['weapon_damage']:
|
||||
damage = Damage()
|
||||
damage.load_json(damage_data)
|
||||
self.weapon_damage.append(damage)
|
||||
self.weapon_attack_anim_right = data['weapon_attack_anim_right']
|
||||
self.weapon_attack_anim_left = data['weapon_attack_anim_left']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['weapon_wepspeed'] = self.weapon_wepspeed
|
||||
data['weapon_max_range'] = self.weapon_max_range
|
||||
data['weapon_projectile_id'] = self.weapon_projectile_id
|
||||
data['weapon_projectile_speed'] = self.weapon_projectile_speed
|
||||
data['weapon_combat_idle_anim'] = self.weapon_combat_idle_anim
|
||||
data['weapon_damage'] = []
|
||||
for damage in self.weapon_damage:
|
||||
data['weapon_damage'].append(damage.save_json())
|
||||
data['weapon_attack_anim_right'] = self.weapon_attack_anim_right
|
||||
data['weapon_attack_anim_left'] = self.weapon_attack_anim_left
|
||||
return data
|
||||
|
||||
|
||||
class ArcItem(ArcCombatObj):
|
||||
def load_binary(self, stream: ResStream):
|
||||
super().load_binary(stream)
|
||||
self.item_type = stream.read_dword()
|
||||
self.item_eq_slots_value = stream.read_dword()
|
||||
self.item_eq_slots_or = stream.read_dword()
|
||||
self.item_eq_slots_and = stream.read_dword()
|
||||
self.item_eq_slots_type = stream.read_bool()
|
||||
self.item_takeable = stream.read_bool()
|
||||
self.item_value = stream.read_dword()
|
||||
self.item_wt = stream.read_dword()
|
||||
self.item_passive_defense_mod = stream.read_float()
|
||||
self.item_base_name = stream.read_string()
|
||||
self.item_dsc = stream.read_string()
|
||||
self.item_render_object_female = stream.read_qword()
|
||||
self.item_health_full = stream.read_float()
|
||||
self.item_skill_used = stream.read_dword()
|
||||
self.item_skill_mastery_used = stream.read_dword()
|
||||
self.item_parry_anim_id = stream.read_dword()
|
||||
num_adjustments = stream.read_dword()
|
||||
self.item_offering_info = [Offerings() for _ in range(num_adjustments)]
|
||||
for offering in self.item_offering_info:
|
||||
offering.load_binary(stream)
|
||||
|
||||
if self.item_type == ITEM_TYPE_WEAPON:
|
||||
self.item_weapon = Weapon()
|
||||
self.item_weapon.load_binary(stream)
|
||||
self.item_primary_attr = stream.read_dword()
|
||||
self.item_secondary_attr = stream.read_dword()
|
||||
|
||||
if self.item_type == ITEM_TYPE_ARMOR:
|
||||
self.item_bulk_factor = stream.read_float()
|
||||
self.item_defense_rating = stream.read_dword()
|
||||
self.item_flags = stream.read_dword()
|
||||
self.item_use_flags = stream.read_dword()
|
||||
self.item_post_item_id = stream.read_qword()
|
||||
self.item_initial_charges = stream.read_dword()
|
||||
self.item_book_arcana = stream.read_dword()
|
||||
num_skills = stream.read_dword()
|
||||
self.item_skill_req = [SkillLevel() for _ in range(num_skills)]
|
||||
for skill in self.item_skill_req:
|
||||
skill.load_binary(stream)
|
||||
self.item_race_req = RaceRequired()
|
||||
self.item_race_req.load_binary(stream)
|
||||
self.item_class_req = ClassRequired()
|
||||
self.item_class_req.load_binary(stream)
|
||||
self.item_disc_req = DiscRequired()
|
||||
self.item_disc_req.load_binary(stream)
|
||||
num_attrs = stream.read_dword()
|
||||
self.item_attr_req = [AttributeValue() for _ in range(num_attrs)]
|
||||
for attr in self.item_attr_req:
|
||||
attr.load_binary(stream)
|
||||
self.item_level_req = stream.read_dword()
|
||||
self.item_rank_req = stream.read_dword()
|
||||
self.item_sex_req = stream.read_dword()
|
||||
num_user_actions = stream.read_dword()
|
||||
self.item_user_power_action = [
|
||||
[
|
||||
stream.read_dword(),
|
||||
stream.read_dword(),
|
||||
stream.read_dword(),
|
||||
] for _ in range(num_user_actions)
|
||||
]
|
||||
num_power_grants = stream.read_dword()
|
||||
self.item_power_grant = [PowerGrant() for _ in range(num_power_grants)]
|
||||
for action in self.item_power_grant:
|
||||
action.load_binary(stream)
|
||||
num_power_actions = stream.read_dword()
|
||||
self.item_power_action = [PowerAction() for _ in range(num_power_actions)]
|
||||
for grant in self.item_power_action:
|
||||
grant.load_binary(stream)
|
||||
|
||||
self.item_sheathable = stream.read_bool()
|
||||
if self.item_sheathable:
|
||||
self.item_sheath_slot = stream.read_dword()
|
||||
self.item_sheath_offset = stream.read_tuple()
|
||||
self.item_sheath_rotation = stream.read_tuple()
|
||||
|
||||
self.item_has_stub = stream.read_bool()
|
||||
if self.item_has_stub:
|
||||
self.item_stub_holder = [
|
||||
stream.read_bool(),
|
||||
stream.read_qword(),
|
||||
]
|
||||
num_adjustments = stream.read_dword()
|
||||
self.item_offering_adjustments = [Offerings() for _ in range(num_adjustments)]
|
||||
for offering in self.item_offering_adjustments:
|
||||
offering.load_binary(stream)
|
||||
num_costs = stream.read_dword()
|
||||
self.item_resource_costs = [ResourceInfo() for _ in range(num_costs)]
|
||||
for res in self.item_resource_costs:
|
||||
res.load_binary(stream)
|
||||
self.item_bane_rank = stream.read_dword()
|
||||
self.item_ignore_saved_actions = stream.read_bool()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
super().save_binary(stream)
|
||||
stream.write_dword(self.item_type)
|
||||
stream.write_dword(self.item_eq_slots_value)
|
||||
stream.write_dword(self.item_eq_slots_or)
|
||||
stream.write_dword(self.item_eq_slots_and)
|
||||
stream.write_bool(self.item_eq_slots_type)
|
||||
stream.write_bool(self.item_takeable)
|
||||
stream.write_dword(self.item_value)
|
||||
stream.write_dword(self.item_wt)
|
||||
stream.write_float(self.item_passive_defense_mod)
|
||||
stream.write_string(self.item_base_name)
|
||||
stream.write_string(self.item_dsc)
|
||||
stream.write_qword(self.item_render_object_female)
|
||||
stream.write_float(self.item_health_full)
|
||||
stream.write_dword(self.item_skill_used)
|
||||
stream.write_dword(self.item_skill_mastery_used)
|
||||
stream.write_dword(self.item_parry_anim_id)
|
||||
stream.write_dword(len(self.item_offering_info))
|
||||
for offering in self.item_offering_info:
|
||||
offering.save_binary(stream)
|
||||
if self.item_type == ITEM_TYPE_WEAPON:
|
||||
self.item_weapon.save_binary(stream)
|
||||
stream.write_dword(self.item_primary_attr)
|
||||
stream.write_dword(self.item_secondary_attr)
|
||||
if self.item_type == ITEM_TYPE_ARMOR:
|
||||
stream.write_float(self.item_bulk_factor)
|
||||
stream.write_dword(self.item_defense_rating)
|
||||
stream.write_dword(self.item_flags)
|
||||
stream.write_dword(self.item_use_flags)
|
||||
stream.write_qword(self.item_post_item_id)
|
||||
stream.write_dword(self.item_initial_charges)
|
||||
stream.write_dword(self.item_book_arcana)
|
||||
stream.write_dword(len(self.item_skill_req))
|
||||
for skill in self.item_skill_req:
|
||||
skill.save_binary(stream)
|
||||
self.item_race_req.save_binary(stream)
|
||||
self.item_class_req.save_binary(stream)
|
||||
self.item_disc_req.save_binary(stream)
|
||||
stream.write_dword(len(self.item_attr_req))
|
||||
for attr in self.item_attr_req:
|
||||
attr.save_binary(stream)
|
||||
stream.write_dword(self.item_level_req)
|
||||
stream.write_dword(self.item_rank_req)
|
||||
stream.write_dword(self.item_sex_req)
|
||||
stream.write_dword(len(self.item_user_power_action))
|
||||
for power in self.item_user_power_action:
|
||||
stream.write_dword(power[0])
|
||||
stream.write_dword(power[1])
|
||||
stream.write_dword(power[2])
|
||||
stream.write_dword(len(self.item_power_grant))
|
||||
for action in self.item_power_grant:
|
||||
action.save_binary(stream)
|
||||
stream.write_dword(len(self.item_power_action))
|
||||
for grant in self.item_power_action:
|
||||
grant.save_binary(stream)
|
||||
stream.write_bool(self.item_sheathable)
|
||||
if self.item_sheathable:
|
||||
stream.write_dword(self.item_sheath_slot)
|
||||
stream.write_tuple(self.item_sheath_offset)
|
||||
stream.write_tuple(self.item_sheath_rotation)
|
||||
stream.write_bool(self.item_has_stub)
|
||||
if self.item_has_stub:
|
||||
stream.write_bool(self.item_stub_holder[0])
|
||||
stream.write_qword(self.item_stub_holder[1])
|
||||
stream.write_dword(len(self.item_offering_adjustments))
|
||||
for offering in self.item_offering_adjustments:
|
||||
offering.save_binary(stream)
|
||||
stream.write_dword(len(self.item_resource_costs))
|
||||
for res in self.item_resource_costs:
|
||||
res.save_binary(stream)
|
||||
stream.write_dword(self.item_bane_rank)
|
||||
stream.write_bool(self.item_ignore_saved_actions)
|
||||
|
||||
def load_json(self, data):
|
||||
super().load_json(data)
|
||||
self.item_type = STRING_TO_ITEM_TYPE[data['item_type']]
|
||||
self.item_eq_slots_value = data['item_eq_slots_value']
|
||||
self.item_eq_slots_type = data['item_eq_slots_type']
|
||||
value = 0
|
||||
for i in range(ITEM_EQUIP_SLOT_NUM):
|
||||
eq_slot = 1 << i
|
||||
if ITEM_EQIP_SLOT_TO_STRING[eq_slot] in data['item_eq_slots_or']:
|
||||
value |= eq_slot
|
||||
self.item_eq_slots_or = value
|
||||
value = 0
|
||||
for i in range(ITEM_EQUIP_SLOT_NUM):
|
||||
eq_slot = 1 << i
|
||||
if ITEM_EQIP_SLOT_TO_STRING[eq_slot] in data['item_eq_slots_and']:
|
||||
value |= eq_slot
|
||||
self.item_eq_slots_and = value
|
||||
self.item_takeable = data['item_takeable']
|
||||
self.item_value = data['item_value']
|
||||
self.item_wt = data['item_wt']
|
||||
self.item_passive_defense_mod = data['item_passive_defense_mod']
|
||||
self.item_base_name = data['item_base_name']
|
||||
self.item_dsc = data['item_dsc']
|
||||
self.item_render_object_female = data['item_render_object_female']
|
||||
self.item_health_full = data['item_health_full']
|
||||
self.item_skill_used = string_to_hash(data['item_skill_used'])
|
||||
self.item_skill_mastery_used = string_to_hash(data['item_skill_mastery_used'])
|
||||
self.item_parry_anim_id = data['item_parry_anim_id']
|
||||
self.item_offering_info = []
|
||||
for offering_data in data['item_offering_info']:
|
||||
offering = Offerings()
|
||||
offering.load_json(offering_data)
|
||||
self.item_offering_info.append(offering)
|
||||
if self.item_type == ITEM_TYPE_WEAPON:
|
||||
self.item_weapon = Weapon()
|
||||
self.item_weapon.load_json(data['item_weapon'])
|
||||
self.item_primary_attr = string_to_hash(data['item_primary_attr'])
|
||||
self.item_secondary_attr = string_to_hash(data['item_secondary_attr'])
|
||||
if self.item_type == ITEM_TYPE_ARMOR:
|
||||
self.item_bulk_factor = data['item_bulk_factor']
|
||||
self.item_defense_rating = data['item_defense_rating']
|
||||
value = 0
|
||||
for i in range(ITEM_FLAG_NUM):
|
||||
item_flag = 1 << i
|
||||
if ITEM_FLAG_TO_STRING[item_flag] in data['item_flags']:
|
||||
value |= item_flag
|
||||
self.item_flags = value
|
||||
value = 0
|
||||
for i in range(ITEM_USE_FLAGS_NUM):
|
||||
item_use_flag = 1 << i
|
||||
if ITEM_USE_FLAGS_TO_STRING[item_use_flag] in data['item_use_flags']:
|
||||
value |= item_use_flag
|
||||
self.item_use_flags = value
|
||||
self.item_post_item_id = data['item_post_item_id']
|
||||
self.item_initial_charges = data['item_initial_charges']
|
||||
self.item_book_arcana = data['item_book_arcana']
|
||||
self.item_skill_req = []
|
||||
for skill_data in data['item_skill_req']:
|
||||
skill = SkillLevel()
|
||||
skill.load_json(skill_data)
|
||||
self.item_skill_req.append(skill)
|
||||
self.item_race_req = RaceRequired()
|
||||
self.item_race_req.load_json(data['item_race_req'])
|
||||
self.item_class_req = ClassRequired()
|
||||
self.item_class_req.load_json(data['item_class_req'])
|
||||
self.item_disc_req = DiscRequired()
|
||||
self.item_disc_req.load_json(data['item_disc_req'])
|
||||
self.item_attr_req = []
|
||||
for attr_data in data['item_attr_req']:
|
||||
attr = AttributeValue()
|
||||
attr.load_json(attr_data)
|
||||
self.item_attr_req.append(attr)
|
||||
self.item_level_req = data['item_level_req']
|
||||
self.item_rank_req = data['item_rank_req']
|
||||
self.item_sex_req = STRING_TO_ITEM_SEX_REQ[data['item_sex_req']]
|
||||
self.item_user_power_action = []
|
||||
for action in data['item_user_power_action']:
|
||||
self.item_user_power_action.append([
|
||||
string_to_hash(action['power']),
|
||||
action['arguments'][0],
|
||||
action['arguments'][1],
|
||||
])
|
||||
self.item_power_grant = []
|
||||
for grant_data in data['item_power_grant']:
|
||||
grant = PowerGrant()
|
||||
grant.load_json(grant_data)
|
||||
self.item_power_grant.append(grant)
|
||||
self.item_power_action = []
|
||||
for action_data in data['item_power_action']:
|
||||
action = PowerAction()
|
||||
action.load_json(action_data)
|
||||
self.item_power_action.append(action)
|
||||
self.item_sheathable = data['item_sheathable']
|
||||
if self.item_sheathable:
|
||||
self.item_sheath_slot = STRING_TO_ITEM_SHEATHSLOT[data['item_sheath_slot']]
|
||||
self.item_sheath_offset = data['item_sheath_offset']
|
||||
self.item_sheath_rotation = data['item_sheath_rotation']
|
||||
self.item_has_stub = data['item_has_stub']
|
||||
if self.item_has_stub:
|
||||
self.item_stub_holder = data['item_has_stub']
|
||||
self.item_offering_adjustments = []
|
||||
for offering_data in data['item_offering_adjustments']:
|
||||
offering = Offerings()
|
||||
offering.load_json(offering_data)
|
||||
self.item_offering_adjustments.append(offering)
|
||||
self.item_resource_costs = []
|
||||
for res_data in data['item_resource_costs']:
|
||||
res = ResourceInfo()
|
||||
res.load_json(res_data)
|
||||
self.item_resource_costs.append(res)
|
||||
self.item_bane_rank = data['item_bane_rank']
|
||||
self.item_ignore_saved_actions = data['item_ignore_saved_actions']
|
||||
|
||||
def save_json(self):
|
||||
data = super().save_json()
|
||||
data['item_type'] = ITEM_TYPE_TO_STRING[self.item_type]
|
||||
data['item_eq_slots_value'] = self.item_eq_slots_value
|
||||
data['item_eq_slots_type'] = self.item_eq_slots_type
|
||||
if not self.item_eq_slots_or:
|
||||
data['item_eq_slots_or'] = [ITEM_EQIP_SLOT_TO_STRING[ITEM_EQUIP_SLOT_NONE]]
|
||||
else:
|
||||
data['item_eq_slots_or'] = []
|
||||
for i in range(ITEM_EQUIP_SLOT_NUM):
|
||||
eq_slot = 1 << i
|
||||
if self.item_eq_slots_or & eq_slot:
|
||||
data['item_eq_slots_or'].append(ITEM_EQIP_SLOT_TO_STRING[eq_slot])
|
||||
if not self.item_eq_slots_and:
|
||||
data['item_eq_slots_and'] = [ITEM_EQIP_SLOT_TO_STRING[ITEM_EQUIP_SLOT_NONE]]
|
||||
else:
|
||||
data['item_eq_slots_and'] = []
|
||||
for i in range(ITEM_EQUIP_SLOT_NUM):
|
||||
eq_slot = 1 << i
|
||||
if self.item_eq_slots_and & eq_slot:
|
||||
data['item_eq_slots_and'].append(ITEM_EQIP_SLOT_TO_STRING[eq_slot])
|
||||
data['item_takeable'] = self.item_takeable
|
||||
data['item_value'] = self.item_value
|
||||
data['item_wt'] = self.item_wt
|
||||
data['item_passive_defense_mod'] = self.item_passive_defense_mod
|
||||
data['item_base_name'] = self.item_base_name
|
||||
data['item_dsc'] = self.item_dsc
|
||||
data['item_render_object_female'] = self.item_render_object_female
|
||||
data['item_health_full'] = self.item_health_full
|
||||
data['item_skill_used'] = hash_to_string(self.item_skill_used)
|
||||
data['item_skill_mastery_used'] = hash_to_string(self.item_skill_mastery_used)
|
||||
data['item_parry_anim_id'] = self.item_parry_anim_id
|
||||
data['item_offering_info'] = []
|
||||
for offering in self.item_offering_info:
|
||||
data['item_offering_info'].append(offering.save_json())
|
||||
if self.item_type == ITEM_TYPE_WEAPON:
|
||||
data['item_weapon'] = self.item_weapon.save_json()
|
||||
data['item_primary_attr'] = hash_to_string(self.item_primary_attr)
|
||||
data['item_secondary_attr'] = hash_to_string(self.item_secondary_attr)
|
||||
if self.item_type == ITEM_TYPE_ARMOR:
|
||||
data['item_bulk_factor'] = self.item_bulk_factor
|
||||
data['item_defense_rating'] = self.item_defense_rating
|
||||
data['item_flags'] = []
|
||||
if self.item_flags:
|
||||
for i in range(ITEM_FLAG_NUM):
|
||||
item_flag = 1 << i
|
||||
if self.item_flags & item_flag:
|
||||
data['item_flags'].append(ITEM_FLAG_TO_STRING[item_flag])
|
||||
data['item_use_flags'] = []
|
||||
if self.item_use_flags:
|
||||
for i in range(ITEM_USE_FLAGS_NUM):
|
||||
item_use_flag = 1 << i
|
||||
if self.item_use_flags & item_use_flag:
|
||||
data['item_use_flags'].append(ITEM_USE_FLAGS_TO_STRING[item_use_flag])
|
||||
data['item_post_item_id'] = self.item_post_item_id
|
||||
data['item_initial_charges'] = self.item_initial_charges
|
||||
data['item_book_arcana'] = self.item_book_arcana
|
||||
data['item_skill_req'] = []
|
||||
for skill in self.item_skill_req:
|
||||
data['item_skill_req'].append(skill.save_json())
|
||||
data['item_race_req'] = self.item_race_req.save_json()
|
||||
data['item_class_req'] = self.item_class_req.save_json()
|
||||
data['item_disc_req'] = self.item_disc_req.save_json()
|
||||
data['item_attr_req'] = []
|
||||
for attr in self.item_attr_req:
|
||||
data['item_attr_req'].append(attr.save_json())
|
||||
data['item_level_req'] = self.item_level_req
|
||||
data['item_rank_req'] = self.item_rank_req
|
||||
data['item_sex_req'] = ITEM_SEX_REQ_TO_STRING[self.item_sex_req]
|
||||
data['item_user_power_action'] = []
|
||||
for action in self.item_user_power_action:
|
||||
data['item_user_power_action'].append({
|
||||
'power': hash_to_string(action[0]),
|
||||
'arguments': action[1:3],
|
||||
})
|
||||
data['item_power_grant'] = []
|
||||
for grant in self.item_power_grant:
|
||||
data['item_power_grant'].append(grant.save_json())
|
||||
data['item_power_action'] = []
|
||||
for action in self.item_power_action:
|
||||
data['item_power_action'].append(action.save_json())
|
||||
data['item_sheathable'] = self.item_sheathable
|
||||
if self.item_sheathable:
|
||||
data['item_sheath_slot'] = ITEM_SHEATHSLOT_TO_STRING[self.item_sheath_slot]
|
||||
data['item_sheath_offset'] = self.item_sheath_offset
|
||||
data['item_sheath_rotation'] = self.item_sheath_rotation
|
||||
data['item_has_stub'] = self.item_has_stub
|
||||
if self.item_has_stub:
|
||||
data['item_has_stub'] = self.item_stub_holder
|
||||
data['item_offering_adjustments'] = []
|
||||
for offering in self.item_offering_adjustments:
|
||||
data['item_offering_adjustments'].append(offering.save_json())
|
||||
data['item_resource_costs'] = []
|
||||
for res in self.item_resource_costs:
|
||||
data['item_resource_costs'].append(res.save_json())
|
||||
data['item_bane_rank'] = self.item_bane_rank
|
||||
data['item_ignore_saved_actions'] = self.item_ignore_saved_actions
|
||||
return data
|
||||
@@ -0,0 +1,41 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from arcane.util import ResStream
|
||||
from .ArcItem import ArcItem
|
||||
|
||||
|
||||
class ArcKey(ArcItem):
|
||||
def load_binary(self, stream: ResStream):
|
||||
super().load_binary(stream)
|
||||
self.key_keyval = stream.read_qword()
|
||||
self.key_keyval2 = stream.read_qword()
|
||||
self.key_keyval3 = stream.read_qword()
|
||||
self.key_setting = stream.read_dword()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
super().save_binary(stream)
|
||||
stream.write_qword(self.key_keyval)
|
||||
stream.write_qword(self.key_keyval2)
|
||||
stream.write_qword(self.key_keyval3)
|
||||
stream.write_dword(self.key_setting)
|
||||
|
||||
def load_json(self, data):
|
||||
super().load_json(data)
|
||||
self.key_keyval = data['key_keyval']
|
||||
self.key_keyval2 = data['key_keyval2']
|
||||
self.key_keyval3 = data['key_keyval3']
|
||||
self.key_setting = data['key_setting']
|
||||
|
||||
def save_json(self):
|
||||
data = super().save_json()
|
||||
data['key_keyval'] = self.key_keyval
|
||||
data['key_keyval2'] = self.key_keyval2
|
||||
data['key_keyval3'] = self.key_keyval3
|
||||
data['key_setting'] = self.key_setting
|
||||
return data
|
||||
@@ -0,0 +1,148 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.enums.arc_object import *
|
||||
from arcane.enums.hashes import hash_to_string, string_to_hash
|
||||
from arcane.util import ResStream
|
||||
from .common.SparseData import SparseData
|
||||
|
||||
|
||||
class SoundEvent:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.sound_type = stream.read_dword()
|
||||
self.sound_event = stream.read_qword()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.sound_type)
|
||||
stream.write_qword(self.sound_event)
|
||||
|
||||
def load_json(self, data):
|
||||
self.sound_type = STRING_TO_SOUND_TYPE[data['sound_type']]
|
||||
self.sound_event = data['sound_event']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['sound_type'] = SOUND_TYPE_TO_STRING[self.sound_type]
|
||||
data['sound_event'] = self.sound_event
|
||||
return data
|
||||
|
||||
|
||||
class ArcObj:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.obj_name = stream.read_string()
|
||||
self.obj_pickable = stream.read_bool()
|
||||
self.obj_gravity = stream.read_float()
|
||||
self.obj_cull_distance = stream.read_float()
|
||||
self.obj_scale = stream.read_tuple()
|
||||
self.obj_render_object = stream.read_qword()
|
||||
self.obj_double_fusion = stream.read_bool()
|
||||
self.obj_forward_vector = stream.read_tuple()
|
||||
self.obj_tracking_name = stream.read_string()
|
||||
self.obj_max_tracking_distance = stream.read_float()
|
||||
self.obj_icon = stream.read_qword()
|
||||
self.obj_gravity_f = stream.read_float()
|
||||
num_sound_events = stream.read_dword()
|
||||
self.obj_sound_events = [SoundEvent() for _ in range(num_sound_events)]
|
||||
for sound_event in self.obj_sound_events:
|
||||
sound_event.load_binary(stream)
|
||||
num_hard_points = stream.read_dword()
|
||||
self.obj_arc_hardpoint_list = [
|
||||
[
|
||||
stream.read_dword(),
|
||||
stream.read_dword(),
|
||||
[stream.read_float() for _ in range(10)]
|
||||
] for _ in range(num_hard_points)
|
||||
]
|
||||
self.obj_sparse_data = SparseData()
|
||||
self.obj_sparse_data.load_binary(stream)
|
||||
self.obj_render_object_low_detail = stream.read_qword()
|
||||
self.obj_default_alignment = stream.read_tuple()
|
||||
self.obj_sound_table = stream.read_dword()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_string(self.obj_name)
|
||||
stream.write_bool(self.obj_pickable)
|
||||
stream.write_float(self.obj_gravity)
|
||||
stream.write_float(self.obj_cull_distance)
|
||||
stream.write_tuple(self.obj_scale)
|
||||
stream.write_qword(self.obj_render_object)
|
||||
stream.write_bool(self.obj_double_fusion)
|
||||
stream.write_tuple(self.obj_forward_vector)
|
||||
stream.write_string(self.obj_tracking_name)
|
||||
stream.write_float(self.obj_max_tracking_distance)
|
||||
stream.write_qword(self.obj_icon)
|
||||
stream.write_float(self.obj_gravity_f)
|
||||
stream.write_dword(len(self.obj_sound_events))
|
||||
for sound_event in self.obj_sound_events:
|
||||
sound_event.save_binary(stream)
|
||||
stream.write_dword(len(self.obj_arc_hardpoint_list))
|
||||
for n, m, points in self.obj_arc_hardpoint_list:
|
||||
stream.write_dword(n)
|
||||
stream.write_dword(m)
|
||||
for i in range(10):
|
||||
stream.write_float(points[i])
|
||||
self.obj_sparse_data.save_binary(stream)
|
||||
stream.write_qword(self.obj_render_object_low_detail)
|
||||
stream.write_tuple(self.obj_default_alignment)
|
||||
stream.write_dword(self.obj_sound_table)
|
||||
|
||||
def load_json(self, data):
|
||||
self.obj_name = data['obj_name']
|
||||
self.obj_pickable = data['obj_pickable']
|
||||
self.obj_gravity = data['obj_gravity']
|
||||
self.obj_cull_distance = data['obj_cull_distance']
|
||||
self.obj_scale = data['obj_scale']
|
||||
self.obj_render_object = data['obj_render_object']
|
||||
self.obj_double_fusion = data['obj_double_fusion']
|
||||
self.obj_forward_vector = data['obj_forward_vector']
|
||||
self.obj_tracking_name = data['obj_tracking_name']
|
||||
self.obj_max_tracking_distance = data['obj_max_tracking_distance']
|
||||
self.obj_icon = data['obj_icon']
|
||||
self.obj_gravity_f = data['obj_gravity_f']
|
||||
self.obj_sound_events = []
|
||||
for sound_data in data['obj_sound_events']:
|
||||
sound_event = SoundEvent()
|
||||
sound_event.load_json(sound_data)
|
||||
self.obj_sound_events.append(sound_event)
|
||||
self.obj_arc_hardpoint_list = []
|
||||
for point_list in data['obj_arc_hardpoint_list']:
|
||||
self.obj_arc_hardpoint_list.append(point_list)
|
||||
self.obj_sparse_data = SparseData()
|
||||
self.obj_sparse_data.load_json(data['obj_sparse_data'])
|
||||
self.obj_render_object_low_detail = data['obj_render_object_low_detail']
|
||||
self.obj_default_alignment = data['obj_default_alignment']
|
||||
self.obj_sound_table = string_to_hash(data['obj_sound_table'])
|
||||
return data
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['obj_name'] = self.obj_name
|
||||
data['obj_pickable'] = self.obj_pickable
|
||||
data['obj_gravity'] = self.obj_gravity
|
||||
data['obj_cull_distance'] = self.obj_cull_distance
|
||||
data['obj_scale'] = self.obj_scale
|
||||
data['obj_render_object'] = self.obj_render_object
|
||||
data['obj_double_fusion'] = self.obj_double_fusion
|
||||
data['obj_forward_vector'] = self.obj_forward_vector
|
||||
data['obj_tracking_name'] = self.obj_tracking_name
|
||||
data['obj_max_tracking_distance'] = self.obj_max_tracking_distance
|
||||
data['obj_icon'] = self.obj_icon
|
||||
data['obj_gravity_f'] = self.obj_gravity_f
|
||||
data['obj_sound_events'] = []
|
||||
for sound_event in self.obj_sound_events:
|
||||
data['obj_sound_events'].append(sound_event.save_json())
|
||||
data['obj_arc_hardpoint_list'] = []
|
||||
for point_list in self.obj_arc_hardpoint_list:
|
||||
data['obj_arc_hardpoint_list'].append(point_list)
|
||||
data['obj_sparse_data'] = self.obj_sparse_data.save_json()
|
||||
data['obj_render_object_low_detail'] = self.obj_render_object_low_detail
|
||||
data['obj_default_alignment'] = self.obj_default_alignment
|
||||
data['obj_sound_table'] = hash_to_string(self.obj_sound_table)
|
||||
return data
|
||||
@@ -0,0 +1,469 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# 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(string_to_hash(monster))
|
||||
self.rune_helper_monster_types = []
|
||||
for monster in data['rune_helper_monster_types']:
|
||||
self.rune_helper_monster_types.append(string_to_hash(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(hash_to_string(monster))
|
||||
data['rune_helper_monster_types'] = []
|
||||
for monster in self.rune_helper_monster_types:
|
||||
data['rune_helper_monster_types'].append(hash_to_string(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
|
||||
@@ -0,0 +1,101 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.util import ResStream
|
||||
from .ArcCombatObj import ArcCombatObj
|
||||
|
||||
|
||||
class Sound:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.sound_0 = stream.read_qword()
|
||||
self.sound_1 = stream.read_qword()
|
||||
self.sound_min_dist = stream.read_float()
|
||||
self.sound_max_dist = stream.read_float()
|
||||
self.sound_dist = stream.read_bool()
|
||||
self.sound_loop = stream.read_bool()
|
||||
self.sound_chance = stream.read_dword()
|
||||
self.sound_interval = stream.read_float()
|
||||
self.sound_reserved = stream.read_dword()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_qword(self.sound_0)
|
||||
stream.write_qword(self.sound_1)
|
||||
stream.write_float(self.sound_min_dist)
|
||||
stream.write_float(self.sound_max_dist)
|
||||
stream.write_bool(self.sound_dist)
|
||||
stream.write_bool(self.sound_loop)
|
||||
stream.write_dword(self.sound_chance)
|
||||
stream.write_float(self.sound_interval)
|
||||
stream.write_dword(self.sound_reserved)
|
||||
|
||||
def load_json(self, data):
|
||||
self.sound_0 = data['sound_0']
|
||||
self.sound_1 = data['sound_1']
|
||||
self.sound_min_dist = data['sound_min_dist']
|
||||
self.sound_max_dist = data['sound_max_dist']
|
||||
self.sound_dist = data['sound_dist']
|
||||
self.sound_loop = data['sound_loop']
|
||||
self.sound_chance = data['sound_chance']
|
||||
self.sound_interval = data['sound_interval']
|
||||
self.sound_reserved = data['sound_reserved']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['sound_0'] = self.sound_0
|
||||
data['sound_1'] = self.sound_1
|
||||
data['sound_min_dist'] = self.sound_min_dist
|
||||
data['sound_max_dist'] = self.sound_max_dist
|
||||
data['sound_dist'] = self.sound_dist
|
||||
data['sound_loop'] = self.sound_loop
|
||||
data['sound_chance'] = self.sound_chance
|
||||
data['sound_interval'] = self.sound_interval
|
||||
data['sound_reserved'] = self.sound_reserved
|
||||
return data
|
||||
|
||||
|
||||
class ArcStaticObject(ArcCombatObj):
|
||||
def load_binary(self, stream: ResStream):
|
||||
super().load_binary(stream)
|
||||
self.static_platform_height = stream.read_float()
|
||||
self.static_has_platform = stream.read_bool()
|
||||
self.static_collision_detect = stream.read_bool()
|
||||
self.static_has_sound = stream.read_bool()
|
||||
if self.static_has_sound:
|
||||
self.static_sound = Sound()
|
||||
self.static_sound.load_binary(stream)
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
super().save_binary(stream)
|
||||
stream.write_float(self.static_platform_height)
|
||||
stream.write_bool(self.static_has_platform)
|
||||
stream.write_bool(self.static_collision_detect)
|
||||
stream.write_bool(self.static_has_sound)
|
||||
if self.static_has_sound:
|
||||
self.static_sound.save_binary(stream)
|
||||
|
||||
def load_json(self, data):
|
||||
super().load_json(data)
|
||||
self.static_platform_height = data['static_platform_height']
|
||||
self.static_has_platform = data['static_has_platform']
|
||||
self.static_collision_detect = data['static_collision_detect']
|
||||
self.static_has_sound = data['static_has_sound']
|
||||
if self.static_has_sound:
|
||||
self.static_sound = Sound()
|
||||
self.static_sound.load_json(data['static_sound'])
|
||||
|
||||
def save_json(self):
|
||||
data = super().save_json()
|
||||
data['static_platform_height'] = self.static_platform_height
|
||||
data['static_has_platform'] = self.static_has_platform
|
||||
data['static_collision_detect'] = self.static_collision_detect
|
||||
data['static_has_sound'] = self.static_has_sound
|
||||
if self.static_has_sound:
|
||||
data['static_sound'] = self.static_sound.save_json()
|
||||
return data
|
||||
@@ -0,0 +1,330 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.enums.arc_structure import *
|
||||
from arcane.util import ResStream
|
||||
from .ArcDoorObject import ArcDoorObject
|
||||
from .ArcStaticObject import ArcStaticObject
|
||||
|
||||
|
||||
class Region:
|
||||
def load_binary(self, stream: ResStream):
|
||||
num_points = stream.read_dword()
|
||||
self.region_points = [
|
||||
stream.read_tuple() for _ in range(num_points)
|
||||
]
|
||||
self.region_render_scale = stream.read_tuple()
|
||||
self.region_content_behavior = stream.read_dword()
|
||||
self.region_state = stream.read_dword()
|
||||
self.region_render_flipped = stream.read_bool()
|
||||
self.region_has_stairs = stream.read_bool()
|
||||
if self.region_has_stairs:
|
||||
self.region_stairs = [
|
||||
stream.read_byte(),
|
||||
stream.read_byte()
|
||||
]
|
||||
self.region_unknown2 = stream.read_byte()
|
||||
self.region_unknown3 = stream.read_byte()
|
||||
self.region_unknown4 = stream.read_tuple()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(len(self.region_points))
|
||||
for point in self.region_points:
|
||||
stream.write_tuple(point)
|
||||
stream.write_tuple(self.region_render_scale)
|
||||
stream.write_dword(self.region_content_behavior)
|
||||
stream.write_dword(self.region_state)
|
||||
stream.write_bool(self.region_render_flipped)
|
||||
stream.write_bool(self.region_has_stairs)
|
||||
if self.region_has_stairs:
|
||||
stream.write_byte(self.region_stairs[0])
|
||||
stream.write_byte(self.region_stairs[1])
|
||||
stream.write_byte(self.region_unknown2)
|
||||
stream.write_byte(self.region_unknown3)
|
||||
stream.write_tuple(self.region_unknown4)
|
||||
|
||||
def load_json(self, data):
|
||||
self.region_points = data['region_points']
|
||||
self.region_render_scale = data['region_render_scale']
|
||||
self.region_content_behavior = STRING_TO_REGION_CONTENTBEHAVIOR[
|
||||
data['region_content_behavior']
|
||||
]
|
||||
self.region_state = STRING_TO_REGION_STATE[data['region_state']]
|
||||
self.region_render_flipped = data['region_render_flipped']
|
||||
self.region_has_stairs = data['region_has_stairs']
|
||||
if self.region_has_stairs:
|
||||
self.region_stairs = data['region_stairs']
|
||||
self.region_unknown2 = data['region_unknown2']
|
||||
self.region_unknown3 = data['region_unknown3']
|
||||
self.region_unknown4 = data['region_unknown4']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['region_points'] = self.region_points
|
||||
data['region_render_scale'] = self.region_render_scale
|
||||
data['region_content_behavior'] = REGION_CONTENTBEHAVIOR_TO_STRING[
|
||||
self.region_content_behavior
|
||||
]
|
||||
data['region_state'] = REGION_STATE_TO_STRING[self.region_state]
|
||||
data['region_render_flipped'] = self.region_render_flipped
|
||||
data['region_has_stairs'] = self.region_has_stairs
|
||||
if self.region_has_stairs:
|
||||
data['region_stairs'] = self.region_stairs
|
||||
data['region_unknown2'] = self.region_unknown2
|
||||
data['region_unknown3'] = self.region_unknown3
|
||||
data['region_unknown4'] = self.region_unknown4
|
||||
return data
|
||||
|
||||
|
||||
class Room:
|
||||
def load_binary(self, stream: ResStream):
|
||||
num_regions = stream.read_dword()
|
||||
self.room_regions = [Region() for _ in range(num_regions)]
|
||||
for region in self.room_regions:
|
||||
region.load_binary(stream)
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(len(self.room_regions))
|
||||
for region in self.room_regions:
|
||||
region.save_binary(stream)
|
||||
|
||||
def load_json(self, data):
|
||||
self.room_regions = []
|
||||
for region_data in data:
|
||||
region = Region()
|
||||
region.load_json(region_data)
|
||||
self.room_regions.append(region)
|
||||
|
||||
def save_json(self):
|
||||
data = []
|
||||
for region in self.room_regions:
|
||||
data.append(region.save_json())
|
||||
return data
|
||||
|
||||
|
||||
class Floor:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.floor_level_number = stream.read_dword()
|
||||
num_exits = stream.read_dword()
|
||||
self.floor_exits = [Region() for _ in range(num_exits)]
|
||||
for exit in self.floor_exits:
|
||||
exit.load_binary(stream)
|
||||
num_regions = stream.read_dword()
|
||||
self.floor_rooms = [Room() for _ in range(num_regions)]
|
||||
for room in self.floor_rooms:
|
||||
room.load_binary(stream)
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.floor_level_number)
|
||||
stream.write_dword(len(self.floor_exits))
|
||||
for exit in self.floor_exits:
|
||||
exit.save_binary(stream)
|
||||
stream.write_dword(len(self.floor_rooms))
|
||||
for room in self.floor_rooms:
|
||||
room.save_binary(stream)
|
||||
|
||||
def load_json(self, data):
|
||||
self.floor_level_number = data['floor_level_number']
|
||||
self.floor_exits = []
|
||||
for exit_data in data['floor_exits']:
|
||||
exit = Region()
|
||||
exit.load_json(exit_data)
|
||||
self.floor_exits.append(exit)
|
||||
self.floor_rooms = []
|
||||
for room_data in data['floor_rooms']:
|
||||
room = Room()
|
||||
room.load_json(room_data)
|
||||
self.floor_rooms.append(room)
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['floor_level_number'] = self.floor_level_number
|
||||
data['floor_exits'] = []
|
||||
for exit in self.floor_exits:
|
||||
data['floor_exits'].append(exit.save_json())
|
||||
data['floor_rooms'] = []
|
||||
for room in self.floor_rooms:
|
||||
data['floor_rooms'].append(room.save_json())
|
||||
return data
|
||||
|
||||
|
||||
class Hole:
|
||||
def load_binary(self, stream: ResStream):
|
||||
num_edges = stream.read_dword()
|
||||
self.hole_edges = [
|
||||
[
|
||||
stream.read_tuple(),
|
||||
stream.read_tuple()
|
||||
] for _ in range(num_edges)
|
||||
]
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(len(self.hole_edges))
|
||||
for edge in self.hole_edges:
|
||||
stream.write_tuple(edge[0])
|
||||
stream.write_tuple(edge[1])
|
||||
|
||||
def load_json(self, data):
|
||||
self.hole_edges = []
|
||||
for edge in data:
|
||||
self.hole_edges.append(edge)
|
||||
|
||||
def save_json(self):
|
||||
data = []
|
||||
for edge in self.hole_edges:
|
||||
data.append(edge)
|
||||
return data
|
||||
|
||||
|
||||
class Level:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.level_number = stream.read_dword()
|
||||
self.level_type = stream.read_bool()
|
||||
self.level_value = stream.read_qword()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.level_number)
|
||||
stream.write_bool(self.level_type)
|
||||
stream.write_qword(self.level_value)
|
||||
|
||||
def load_json(self, data):
|
||||
self.level_number = data['level_number']
|
||||
self.level_type = STRING_TO_LEVEL_TYPE[data['level_type']]
|
||||
self.level_value = data['level_value']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['level_number'] = self.level_number
|
||||
data['level_type'] = LEVEL_TYPE_TO_STRING[self.level_type]
|
||||
data['level_value'] = self.level_value
|
||||
return data
|
||||
|
||||
|
||||
class RegionTrigger:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.trigger_class_name = stream.read_string()
|
||||
self.trigger_parameters = stream.read_string()
|
||||
self.trigger_level_number = stream.read_dword()
|
||||
self.trigger_room_number = stream.read_dword()
|
||||
self.trigger_region_number = stream.read_dword()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_string(self.trigger_class_name)
|
||||
stream.write_string(self.trigger_parameters)
|
||||
stream.write_dword(self.trigger_level_number)
|
||||
stream.write_dword(self.trigger_room_number)
|
||||
stream.write_dword(self.trigger_region_number)
|
||||
|
||||
def load_json(self, data):
|
||||
self.trigger_class_name = data['trigger_class_name']
|
||||
self.trigger_parameters = data['trigger_parameters']
|
||||
self.trigger_level_number = data['trigger_level_number']
|
||||
self.trigger_room_number = data['trigger_room_number']
|
||||
self.trigger_region_number = data['trigger_region_number']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['trigger_class_name'] = self.trigger_class_name
|
||||
data['trigger_parameters'] = self.trigger_parameters
|
||||
data['trigger_level_number'] = self.trigger_level_number
|
||||
data['trigger_room_number'] = self.trigger_room_number
|
||||
data['trigger_region_number'] = self.trigger_region_number
|
||||
return data
|
||||
|
||||
|
||||
class ArcStructureObject(ArcStaticObject):
|
||||
def load_binary(self, stream: ResStream):
|
||||
super().load_binary(stream)
|
||||
length = stream.read_dword()
|
||||
self.structure_floors = [Floor() for _ in range(length)]
|
||||
for floor in self.structure_floors:
|
||||
floor.load_binary(stream)
|
||||
num_holes = stream.read_dword()
|
||||
self.structure_holes = [Hole() for _ in range(num_holes)]
|
||||
for hole in self.structure_holes:
|
||||
hole.load_binary(stream)
|
||||
num_levels = stream.read_dword()
|
||||
self.structure_levels = [Level() for _ in range(num_levels)]
|
||||
for level in self.structure_levels:
|
||||
level.load_binary(stream)
|
||||
num_doors = stream.read_dword()
|
||||
self.structure_doors = [ArcDoorObject() for _ in range(num_doors)]
|
||||
for door in self.structure_doors:
|
||||
door.load_binary(stream)
|
||||
num_region_triggers = stream.read_dword()
|
||||
self.structure_region_triggers = [RegionTrigger() for _ in range(num_region_triggers)]
|
||||
for trigger in self.structure_region_triggers:
|
||||
trigger.load_binary(stream)
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
super().save_binary(stream)
|
||||
stream.write_dword(len(self.structure_floors))
|
||||
for floor in self.structure_floors:
|
||||
floor.save_binary(stream)
|
||||
stream.write_dword(len(self.structure_holes))
|
||||
for hole in self.structure_holes:
|
||||
hole.save_binary(stream)
|
||||
stream.write_dword(len(self.structure_levels))
|
||||
for level in self.structure_levels:
|
||||
level.save_binary(stream)
|
||||
stream.write_dword(len(self.structure_doors))
|
||||
for door in self.structure_doors:
|
||||
door.save_binary(stream)
|
||||
stream.write_dword(len(self.structure_region_triggers))
|
||||
for trigger in self.structure_region_triggers:
|
||||
trigger.save_binary(stream)
|
||||
|
||||
def load_json(self, data):
|
||||
super().load_json(data)
|
||||
self.structure_floors = []
|
||||
for floor_data in data['structure_floors']:
|
||||
floor = Floor()
|
||||
floor.load_json(floor_data)
|
||||
self.structure_floors.append(floor)
|
||||
self.structure_holes = []
|
||||
for hole_data in data['structure_holes']:
|
||||
hole = Hole()
|
||||
hole.load_json(hole_data)
|
||||
self.structure_holes.append(hole)
|
||||
self.structure_levels = []
|
||||
for level_data in data['structure_levels']:
|
||||
level = Level()
|
||||
level.load_json(level_data)
|
||||
self.structure_levels.append(level)
|
||||
self.structure_doors = []
|
||||
for door_data in data['structure_doors']:
|
||||
door = ArcDoorObject()
|
||||
door.load_json(door_data)
|
||||
self.structure_doors.append(door)
|
||||
self.structure_region_triggers = []
|
||||
for trigger_data in data['structure_region_triggers']:
|
||||
trigger = RegionTrigger()
|
||||
trigger.load_json(trigger_data)
|
||||
self.structure_region_triggers.append(trigger)
|
||||
return data
|
||||
|
||||
def save_json(self):
|
||||
data = super().save_json()
|
||||
data['structure_floors'] = []
|
||||
for floor in self.structure_floors:
|
||||
data['structure_floors'].append(floor.save_json())
|
||||
data['structure_holes'] = []
|
||||
for hole in self.structure_holes:
|
||||
data['structure_holes'].append(hole.save_json())
|
||||
data['structure_levels'] = []
|
||||
for level in self.structure_levels:
|
||||
data['structure_levels'].append(level.save_json())
|
||||
data['structure_doors'] = []
|
||||
for door in self.structure_doors:
|
||||
data['structure_doors'].append(door.save_json())
|
||||
data['structure_region_triggers'] = []
|
||||
for trigger in self.structure_region_triggers:
|
||||
data['structure_region_triggers'].append(trigger.save_json())
|
||||
return data
|
||||
@@ -0,0 +1,21 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from .ArcAssetStructureObject import ArcAssetStructureObject
|
||||
from .ArcCityAssetTemplate import ArcCityAssetTemplate
|
||||
from .ArcCombatObj import ArcCombatObj, ArcCharacter
|
||||
from .ArcContainerObject import ArcContainerObject
|
||||
from .ArcDeed import ArcDeed
|
||||
from .ArcDoorObject import ArcDoorObject
|
||||
from .ArcDungeonUnitObject import ArcDungeonUnitObject, ArcDungeonExitObject, ArcDungeonStairObject
|
||||
from .ArcItem import ArcItem
|
||||
from .ArcKey import ArcKey
|
||||
from .ArcObj import ArcObj
|
||||
from .ArcRune import ArcRune
|
||||
from .ArcStaticObject import ArcStaticObject
|
||||
from .ArcStructureObject import ArcStructureObject
|
||||
@@ -0,0 +1,260 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.enums.hashes import hash_to_string, string_to_hash
|
||||
from arcane.util import ResStream
|
||||
|
||||
|
||||
class AttributeValue:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.attr_type = stream.read_dword()
|
||||
self.attr_value = stream.read_dword()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.attr_type)
|
||||
stream.write_dword(self.attr_value)
|
||||
|
||||
def load_json(self, data):
|
||||
self.attr_type = string_to_hash(data['attr_type'])
|
||||
self.attr_value = data['attr_value']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['attr_type'] = hash_to_string(self.attr_type)
|
||||
data['attr_value'] = self.attr_value
|
||||
return data
|
||||
|
||||
|
||||
class PowerArgument:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.power_arguments = [
|
||||
stream.read_dword(),
|
||||
stream.read_dword(),
|
||||
]
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.power_arguments[0])
|
||||
stream.write_dword(self.power_arguments[1])
|
||||
|
||||
def load_json(self, data):
|
||||
self.power_arguments = data['power_arguments']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['power_arguments'] = self.power_arguments
|
||||
return data
|
||||
|
||||
|
||||
class SkillLevel:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.skill_type = stream.read_dword()
|
||||
self.skill_level = stream.read_dword()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.skill_type)
|
||||
stream.write_dword(self.skill_level)
|
||||
|
||||
def load_json(self, data):
|
||||
self.skill_type = string_to_hash(data['skill_type'])
|
||||
self.skill_level = data['skill_level']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['skill_type'] = hash_to_string(self.skill_type)
|
||||
data['skill_level'] = self.skill_level
|
||||
return data
|
||||
|
||||
|
||||
class ResourceInfo:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.resource_type = stream.read_dword()
|
||||
self.resource_value = stream.read_dword()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.resource_type)
|
||||
stream.write_dword(self.resource_value)
|
||||
|
||||
def load_json(self, data):
|
||||
self.resource_type = string_to_hash(data['resource_type'])
|
||||
self.resource_value = data['resource_value']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['resource_type'] = hash_to_string(self.resource_type)
|
||||
data['resource_value'] = self.resource_value
|
||||
return data
|
||||
|
||||
|
||||
class PowerAction:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.power_type = stream.read_dword()
|
||||
|
||||
num_grants = stream.read_dword()
|
||||
self.power_actions = [PowerArgument() for _ in range(num_grants)]
|
||||
for power in self.power_actions:
|
||||
power.load_binary(stream)
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.power_type)
|
||||
stream.write_dword(len(self.power_actions))
|
||||
for power in self.power_actions:
|
||||
power.save_binary(stream)
|
||||
|
||||
def load_json(self, data):
|
||||
self.power_type = string_to_hash(data['power_type'])
|
||||
self.power_actions = []
|
||||
for power_data in data['power_actions']:
|
||||
power = PowerArgument()
|
||||
power.load_json(power_data)
|
||||
self.power_actions.append(power)
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['power_type'] = hash_to_string(self.power_type)
|
||||
data['power_actions'] = []
|
||||
for power in self.power_actions:
|
||||
data['power_actions'].append(power.save_json())
|
||||
return data
|
||||
|
||||
|
||||
class PowerGrant:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.power_type = stream.read_dword()
|
||||
self.power_value = stream.read_dword()
|
||||
num_attrs = stream.read_dword()
|
||||
self.power_granted_attrs = [
|
||||
[
|
||||
stream.read_dword(),
|
||||
stream.read_dword(),
|
||||
] for _ in range(num_attrs)
|
||||
]
|
||||
num_skills = stream.read_dword()
|
||||
self.power_granted_skills = [
|
||||
[
|
||||
stream.read_dword(),
|
||||
stream.read_dword(),
|
||||
] for _ in range(num_skills)
|
||||
]
|
||||
num_powers = stream.read_dword()
|
||||
self.power_granted_powers = [
|
||||
[
|
||||
stream.read_dword(),
|
||||
stream.read_dword(),
|
||||
] for _ in range(num_powers)
|
||||
]
|
||||
num_monster_types = stream.read_dword()
|
||||
self.power_monster_types = [
|
||||
stream.read_dword() for _ in range(num_monster_types)
|
||||
]
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.power_type)
|
||||
stream.write_dword(self.power_value)
|
||||
stream.write_dword(len(self.power_granted_attrs))
|
||||
for attr in self.power_granted_attrs:
|
||||
stream.write_dword(attr[0])
|
||||
stream.write_dword(attr[1])
|
||||
stream.write_dword(len(self.power_granted_skills))
|
||||
for skill in self.power_granted_skills:
|
||||
stream.write_dword(skill[0])
|
||||
stream.write_dword(skill[1])
|
||||
stream.write_dword(len(self.power_granted_powers))
|
||||
for power in self.power_granted_powers:
|
||||
stream.write_dword(power[0])
|
||||
stream.write_dword(power[1])
|
||||
stream.write_dword(len(self.power_monster_types))
|
||||
for value in self.power_monster_types:
|
||||
stream.write_dword(value)
|
||||
|
||||
def load_json(self, data):
|
||||
self.power_type = string_to_hash(data['power_type'])
|
||||
self.power_value = data['power_value']
|
||||
self.power_granted_attrs = data['power_granted_attrs']
|
||||
self.power_granted_skills = data['power_granted_skills']
|
||||
self.power_granted_powers = data['power_granted_powers']
|
||||
self.power_monster_types = data['power_monster_types']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['power_type'] = hash_to_string(self.power_type)
|
||||
data['power_value'] = self.power_value
|
||||
data['power_granted_attrs'] = self.power_granted_attrs
|
||||
data['power_granted_skills'] = self.power_granted_skills
|
||||
data['power_granted_powers'] = self.power_granted_powers
|
||||
data['power_monster_types'] = self.power_monster_types
|
||||
return data
|
||||
|
||||
|
||||
class SkillGrant:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.skill_type = stream.read_dword()
|
||||
self.skill_value = stream.read_dword()
|
||||
num_attrs = stream.read_dword()
|
||||
self.skill_granted_attrs = [
|
||||
[
|
||||
stream.read_dword(),
|
||||
stream.read_dword(),
|
||||
] for _ in range(num_attrs)
|
||||
]
|
||||
num_skills = stream.read_dword()
|
||||
self.skill_granted_skills = [
|
||||
[
|
||||
stream.read_dword(),
|
||||
stream.read_dword(),
|
||||
] for _ in range(num_skills)
|
||||
]
|
||||
num_powers = stream.read_dword()
|
||||
self.skill_granted_powers = [
|
||||
[
|
||||
stream.read_dword(),
|
||||
stream.read_dword(),
|
||||
] for _ in range(num_powers)
|
||||
]
|
||||
num_monster_types = stream.read_dword()
|
||||
self.skill_monster_types = [
|
||||
stream.read_dword() for _ in range(num_monster_types)
|
||||
]
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.skill_type)
|
||||
stream.write_dword(self.skill_value)
|
||||
stream.write_dword(len(self.skill_granted_attrs))
|
||||
for attr in self.skill_granted_attrs:
|
||||
stream.write_dword(attr[0])
|
||||
stream.write_dword(attr[1])
|
||||
stream.write_dword(len(self.skill_granted_skills))
|
||||
for skill in self.skill_granted_skills:
|
||||
stream.write_dword(skill[0])
|
||||
stream.write_dword(skill[1])
|
||||
stream.write_dword(len(self.skill_granted_powers))
|
||||
for power in self.skill_granted_powers:
|
||||
stream.write_dword(power[0])
|
||||
stream.write_dword(power[1])
|
||||
stream.write_dword(len(self.skill_monster_types))
|
||||
for value in self.skill_monster_types:
|
||||
stream.write_dword(value)
|
||||
|
||||
def load_json(self, data):
|
||||
self.skill_type = string_to_hash(data['skill_type'])
|
||||
self.skill_value = data['skill_value']
|
||||
self.skill_granted_attrs = data['skill_granted_attrs']
|
||||
self.skill_granted_skills = data['skill_granted_skills']
|
||||
self.skill_granted_powers = data['skill_granted_powers']
|
||||
self.skill_monster_types = data['skill_monster_types']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['skill_type'] = hash_to_string(self.skill_type)
|
||||
data['skill_value'] = self.skill_value
|
||||
data['skill_granted_attrs'] = self.skill_granted_attrs
|
||||
data['skill_granted_skills'] = self.skill_granted_skills
|
||||
data['skill_granted_powers'] = self.skill_granted_powers
|
||||
data['skill_monster_types'] = self.skill_monster_types
|
||||
return data
|
||||
@@ -0,0 +1,42 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.enums.hashes import hash_to_string, string_to_hash
|
||||
from arcane.util import ResStream
|
||||
|
||||
|
||||
class ClassRequired:
|
||||
def load_binary(self, stream: ResStream):
|
||||
classs = stream.read_dword()
|
||||
self.class_restrict = stream.read_bool()
|
||||
self.class_values = [
|
||||
stream.read_dword() for _ in range(classs)
|
||||
]
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(len(self.class_values))
|
||||
stream.write_bool(self.class_restrict)
|
||||
for cls in self.class_values:
|
||||
stream.write_dword(cls)
|
||||
|
||||
def load_json(self, data):
|
||||
self.class_restrict = data['restrict']
|
||||
self.class_values = []
|
||||
for cls in data['classes']:
|
||||
self.class_values.append(string_to_hash(cls))
|
||||
return data
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['restrict'] = self.class_restrict
|
||||
data['classes'] = []
|
||||
for cls in self.class_values:
|
||||
data['classes'].append(hash_to_string(cls))
|
||||
return data
|
||||
@@ -0,0 +1,41 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.enums.hashes import hash_to_string, string_to_hash
|
||||
from arcane.util import ResStream
|
||||
|
||||
|
||||
class DiscRequired:
|
||||
def load_binary(self, stream: ResStream):
|
||||
discs = stream.read_dword()
|
||||
self.disc_restrict = stream.read_bool()
|
||||
self.disc_values = [
|
||||
stream.read_dword() for _ in range(discs)
|
||||
]
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(len(self.disc_values))
|
||||
stream.write_bool(self.disc_restrict)
|
||||
for disc in self.disc_values:
|
||||
stream.write_dword(disc)
|
||||
|
||||
def load_json(self, data):
|
||||
self.disc_restrict = data['restrict']
|
||||
self.disc_values = []
|
||||
for disc in data['discs']:
|
||||
self.disc_values.append(string_to_hash(disc))
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['restrict'] = self.disc_restrict
|
||||
data['discs'] = []
|
||||
for disc in self.disc_values:
|
||||
data['discs'].append(hash_to_string(disc))
|
||||
return data
|
||||
@@ -0,0 +1,67 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.enums.common.arc_inventory import *
|
||||
from arcane.util import ResStream
|
||||
|
||||
|
||||
class Inventory:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.inventory_type = stream.read_dword()
|
||||
|
||||
if self.inventory_type == INVENTORY_TYPE_GOLD:
|
||||
self.inventory_gold = [
|
||||
stream.read_float(),
|
||||
stream.read_float(),
|
||||
stream.read_float(),
|
||||
]
|
||||
elif self.inventory_type == INVENTORY_TYPE_ITEM:
|
||||
self.inventory_items = [
|
||||
stream.read_float(),
|
||||
stream.read_qword(),
|
||||
]
|
||||
elif self.inventory_type == INVENTORY_TYPE_BOOTYTABLE:
|
||||
self.inventory_table = [
|
||||
stream.read_float(),
|
||||
stream.read_dword(),
|
||||
]
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.inventory_type)
|
||||
if self.inventory_type == INVENTORY_TYPE_GOLD:
|
||||
stream.write_float(self.inventory_gold[0])
|
||||
stream.write_float(self.inventory_gold[1])
|
||||
stream.write_float(self.inventory_gold[2])
|
||||
elif self.inventory_type == INVENTORY_TYPE_ITEM:
|
||||
stream.write_float(self.inventory_items[0])
|
||||
stream.write_qword(self.inventory_items[1])
|
||||
elif self.inventory_type == INVENTORY_TYPE_BOOTYTABLE:
|
||||
stream.write_float(self.inventory_table[0])
|
||||
stream.write_dword(self.inventory_table[1])
|
||||
|
||||
def load_json(self, data):
|
||||
self.inventory_type = STRING_TO_INVENTORY_TYPE[data['type']]
|
||||
if self.inventory_type == INVENTORY_TYPE_GOLD:
|
||||
self.inventory_gold = data['gold']
|
||||
elif self.inventory_type == INVENTORY_TYPE_ITEM:
|
||||
self.inventory_items = data['items']
|
||||
elif self.inventory_type == INVENTORY_TYPE_BOOTYTABLE:
|
||||
self.inventory_table = data['table']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['type'] = INVENTORY_TYPE_TO_STRING[self.inventory_type]
|
||||
if self.inventory_type == INVENTORY_TYPE_GOLD:
|
||||
data['gold'] = self.inventory_gold
|
||||
elif self.inventory_type == INVENTORY_TYPE_ITEM:
|
||||
data['items'] = self.inventory_items
|
||||
elif self.inventory_type == INVENTORY_TYPE_BOOTYTABLE:
|
||||
data['table'] = self.inventory_table
|
||||
return data
|
||||
@@ -0,0 +1,41 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.enums.hashes import hash_to_string, string_to_hash
|
||||
from arcane.util import ResStream
|
||||
|
||||
|
||||
class RaceRequired:
|
||||
def load_binary(self, stream: ResStream):
|
||||
races = stream.read_dword()
|
||||
self.race_restrict = stream.read_bool()
|
||||
self.race_values = [
|
||||
stream.read_dword() for _ in range(races)
|
||||
]
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(len(self.race_values))
|
||||
stream.write_bool(self.race_restrict)
|
||||
for race in self.race_values:
|
||||
stream.write_dword(race)
|
||||
|
||||
def load_json(self, data):
|
||||
self.race_restrict = data['restrict']
|
||||
self.race_values = []
|
||||
for race in data['races']:
|
||||
self.race_values.append(string_to_hash(race))
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['restrict'] = self.race_restrict
|
||||
data['races'] = []
|
||||
for race in self.race_values:
|
||||
data['races'].append(hash_to_string(race))
|
||||
return data
|
||||
@@ -0,0 +1,108 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.enums.arc_sparse import *
|
||||
from arcane.util import ResStream
|
||||
|
||||
|
||||
class SparseData:
|
||||
def __init__(self) -> None:
|
||||
self.sp_data = OrderedDict()
|
||||
|
||||
def load_binary(self, stream: ResStream):
|
||||
sparse_tag = stream.read_dword()
|
||||
while sparse_tag:
|
||||
sparse_type = SPARSE_TAG_TO_SPARSE_TYPE[sparse_tag]
|
||||
value = None
|
||||
|
||||
if sparse_type == SPARSE_VAL_LONG:
|
||||
value = stream.read_dword()
|
||||
|
||||
elif sparse_type == SPARSE_VAL_FLOAT:
|
||||
value = stream.read_float()
|
||||
|
||||
elif sparse_type == SPARSE_VAL_BOOL:
|
||||
value = stream.read_bool()
|
||||
|
||||
elif sparse_type == SPARSE_UID:
|
||||
value = stream.read_dword()
|
||||
|
||||
elif sparse_type == SPARSE_REF_VECTOR3:
|
||||
value = stream.read_tuple()
|
||||
|
||||
elif sparse_type == SPARSE_REF_ARC_STRING:
|
||||
value = stream.read_string()
|
||||
|
||||
elif sparse_type == SPARSE_REF_MERCHANT_DATA:
|
||||
value = [
|
||||
stream.read_qword(),
|
||||
stream.read_qword(),
|
||||
stream.read_dword(),
|
||||
]
|
||||
|
||||
elif sparse_type == SPARSE_REF_ARC_CACHE_ID:
|
||||
value = stream.read_qword()
|
||||
|
||||
elif sparse_type == SPARSE_PTR_ACTION_RESPONSE:
|
||||
value = stream.read_dword()
|
||||
|
||||
elif sparse_type == SPARSE_ENUM_ITEM_TYPE:
|
||||
value = stream.read_dword()
|
||||
|
||||
self.sp_data[sparse_tag] = value
|
||||
sparse_tag = stream.read_dword()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
for tag, value in self.sp_data.items():
|
||||
stream.write_dword(tag)
|
||||
|
||||
sparse_type = SPARSE_TAG_TO_SPARSE_TYPE[tag]
|
||||
if sparse_type == SPARSE_VAL_LONG:
|
||||
stream.write_dword(value)
|
||||
|
||||
elif sparse_type == SPARSE_VAL_FLOAT:
|
||||
stream.write_float(value)
|
||||
|
||||
elif sparse_type == SPARSE_VAL_BOOL:
|
||||
stream.write_bool(value)
|
||||
|
||||
elif sparse_type == SPARSE_UID:
|
||||
stream.write_dword(value)
|
||||
|
||||
elif sparse_type == SPARSE_REF_VECTOR3:
|
||||
stream.write_tuple(value)
|
||||
|
||||
elif sparse_type == SPARSE_REF_ARC_STRING:
|
||||
stream.write_string(value)
|
||||
|
||||
elif sparse_type == SPARSE_REF_MERCHANT_DATA:
|
||||
stream.write_qword(value[0])
|
||||
stream.write_qword(value[1])
|
||||
stream.write_qword(value[2])
|
||||
|
||||
elif sparse_type == SPARSE_REF_ARC_CACHE_ID:
|
||||
stream.write_qword(value)
|
||||
|
||||
elif sparse_type == SPARSE_PTR_ACTION_RESPONSE:
|
||||
stream.write_dword(value)
|
||||
|
||||
elif sparse_type == SPARSE_ENUM_ITEM_TYPE:
|
||||
stream.write_dword(value)
|
||||
stream.write_dword(0)
|
||||
|
||||
def load_json(self, data):
|
||||
for key, value in data.items():
|
||||
self.sp_data[STRING_TO_SPARSE_TAG[key]] = value
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
for tag, value in self.sp_data.items():
|
||||
data[SPARSE_TAG_TO_STRING[tag]] = value
|
||||
return data
|
||||
@@ -0,0 +1,7 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
Reference in New Issue
Block a user