The inventory read when mobile_has_content is set overwrote one attribute per field, never loaded its power action list and had no save or JSON methods. InstanceInfo follows InstanceInfo_ctorFromStream (sb.exe 0x674810); field names come from InstanceInfo::ParseKeyword (0x66FA60). Power action entries (0x54F680) keep the item power action id/arguments layout; their remaining fields are unknownN. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
274 lines
15 KiB
Python
274 lines
15 KiB
Python
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
|
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
|
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
|
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
|
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
|
# 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 PowerActionInfo:
|
|
def load_binary(self, stream: ResStream):
|
|
self.power_action_id = stream.read_dword()
|
|
self.power_action_arguments = [
|
|
stream.read_long(),
|
|
stream.read_long(),
|
|
]
|
|
self.power_action_has_cache_id = stream.read_bool()
|
|
if self.power_action_has_cache_id:
|
|
self.power_action_cache_id = stream.read_qword()
|
|
else:
|
|
self.power_action_unknown1 = stream.read_dword()
|
|
self.power_action_unknown2 = stream.read_string()
|
|
self.power_action_unknown3 = stream.read_float()
|
|
|
|
def save_binary(self, stream: ResStream):
|
|
stream.write_dword(self.power_action_id)
|
|
stream.write_long(self.power_action_arguments[0])
|
|
stream.write_long(self.power_action_arguments[1])
|
|
stream.write_bool(self.power_action_has_cache_id)
|
|
if self.power_action_has_cache_id:
|
|
stream.write_qword(self.power_action_cache_id)
|
|
else:
|
|
stream.write_dword(self.power_action_unknown1)
|
|
stream.write_string(self.power_action_unknown2)
|
|
stream.write_float(self.power_action_unknown3)
|
|
|
|
def save_json(self):
|
|
data = OrderedDict()
|
|
data['power_action_id'] = hash_to_string(self.power_action_id)
|
|
data['power_action_arguments'] = self.power_action_arguments
|
|
data['power_action_has_cache_id'] = self.power_action_has_cache_id
|
|
if self.power_action_has_cache_id:
|
|
data['power_action_cache_id'] = self.power_action_cache_id
|
|
else:
|
|
data['power_action_unknown1'] = self.power_action_unknown1
|
|
data['power_action_unknown2'] = self.power_action_unknown2
|
|
data['power_action_unknown3'] = self.power_action_unknown3
|
|
return data
|
|
|
|
def load_json(self, data):
|
|
self.power_action_id = string_to_hash(data['power_action_id'])
|
|
self.power_action_arguments = data['power_action_arguments']
|
|
self.power_action_has_cache_id = data['power_action_has_cache_id']
|
|
if self.power_action_has_cache_id:
|
|
self.power_action_cache_id = data['power_action_cache_id']
|
|
else:
|
|
self.power_action_unknown1 = data['power_action_unknown1']
|
|
self.power_action_unknown2 = data['power_action_unknown2']
|
|
self.power_action_unknown3 = data['power_action_unknown3']
|
|
|
|
|
|
class InstanceInfo:
|
|
def load_binary(self, stream: ResStream):
|
|
self.instance_template_id = stream.read_qword()
|
|
self.instance_id = stream.read_qword()
|
|
self.instance_location = stream.read_tuple()
|
|
self.instance_scale = stream.read_tuple()
|
|
self.instance_orientation = [stream.read_float() for _ in range(4)]
|
|
self.instance_container_id = stream.read_qword()
|
|
self.instance_level_number = stream.read_long()
|
|
self.instance_room_number = stream.read_long()
|
|
self.instance_color = stream.read_long()
|
|
self.instance_gravity = stream.read_bool()
|
|
self.instance_name_override = stream.read_string()
|
|
self.instance_has_health = stream.read_bool()
|
|
if self.instance_has_health:
|
|
self.instance_health_full = stream.read_float()
|
|
self.instance_health_current = stream.read_float()
|
|
self.instance_has_item_data = stream.read_bool()
|
|
if self.instance_has_item_data:
|
|
self.instance_maker_id = stream.read_qword()
|
|
self.instance_value = stream.read_long()
|
|
self.instance_mod_value = stream.read_long()
|
|
self.instance_drop_chance = stream.read_float()
|
|
self.instance_flags = stream.read_dword()
|
|
self.instance_charges = stream.read_long()
|
|
num_power_actions = stream.read_dword()
|
|
self.instance_power_actions = [PowerActionInfo() for _ in range(num_power_actions)]
|
|
for power_action in self.instance_power_actions:
|
|
power_action.load_binary(stream)
|
|
self.instance_stack_count = stream.read_long()
|
|
self.instance_has_key_data = stream.read_bool()
|
|
if self.instance_has_key_data:
|
|
self.instance_key_ids = [stream.read_qword() for _ in range(3)]
|
|
self.instance_key_setting = stream.read_long()
|
|
self.instance_has_deed_data = stream.read_bool()
|
|
if self.instance_has_deed_data:
|
|
self.instance_deed_id = stream.read_qword()
|
|
self.instance_deed_rank = stream.read_long()
|
|
self.instance_has_platform_data = stream.read_bool()
|
|
if self.instance_has_platform_data:
|
|
self.instance_has_platform = stream.read_bool()
|
|
self.instance_platform_height = stream.read_float()
|
|
self.instance_damage_flags = stream.read_dword()
|
|
self.instance_map_type = stream.read_long()
|
|
self.instance_has_guild_crest = stream.read_bool()
|
|
if self.instance_has_guild_crest:
|
|
self.instance_guild_crest = [stream.read_long() for _ in range(5)]
|
|
self.instance_has_nation_crest = stream.read_bool()
|
|
if self.instance_has_nation_crest:
|
|
self.instance_nation_crest = [stream.read_long() for _ in range(5)]
|
|
self.instance_is_descriptor = stream.read_bool()
|
|
|
|
def save_binary(self, stream: ResStream):
|
|
stream.write_qword(self.instance_template_id)
|
|
stream.write_qword(self.instance_id)
|
|
stream.write_tuple(self.instance_location)
|
|
stream.write_tuple(self.instance_scale)
|
|
for value in self.instance_orientation:
|
|
stream.write_float(value)
|
|
stream.write_qword(self.instance_container_id)
|
|
stream.write_long(self.instance_level_number)
|
|
stream.write_long(self.instance_room_number)
|
|
stream.write_long(self.instance_color)
|
|
stream.write_bool(self.instance_gravity)
|
|
stream.write_string(self.instance_name_override)
|
|
stream.write_bool(self.instance_has_health)
|
|
if self.instance_has_health:
|
|
stream.write_float(self.instance_health_full)
|
|
stream.write_float(self.instance_health_current)
|
|
stream.write_bool(self.instance_has_item_data)
|
|
if self.instance_has_item_data:
|
|
stream.write_qword(self.instance_maker_id)
|
|
stream.write_long(self.instance_value)
|
|
stream.write_long(self.instance_mod_value)
|
|
stream.write_float(self.instance_drop_chance)
|
|
stream.write_dword(self.instance_flags)
|
|
stream.write_long(self.instance_charges)
|
|
stream.write_dword(len(self.instance_power_actions))
|
|
for power_action in self.instance_power_actions:
|
|
power_action.save_binary(stream)
|
|
stream.write_long(self.instance_stack_count)
|
|
stream.write_bool(self.instance_has_key_data)
|
|
if self.instance_has_key_data:
|
|
for key_id in self.instance_key_ids:
|
|
stream.write_qword(key_id)
|
|
stream.write_long(self.instance_key_setting)
|
|
stream.write_bool(self.instance_has_deed_data)
|
|
if self.instance_has_deed_data:
|
|
stream.write_qword(self.instance_deed_id)
|
|
stream.write_long(self.instance_deed_rank)
|
|
stream.write_bool(self.instance_has_platform_data)
|
|
if self.instance_has_platform_data:
|
|
stream.write_bool(self.instance_has_platform)
|
|
stream.write_float(self.instance_platform_height)
|
|
stream.write_dword(self.instance_damage_flags)
|
|
stream.write_long(self.instance_map_type)
|
|
stream.write_bool(self.instance_has_guild_crest)
|
|
if self.instance_has_guild_crest:
|
|
for value in self.instance_guild_crest:
|
|
stream.write_long(value)
|
|
stream.write_bool(self.instance_has_nation_crest)
|
|
if self.instance_has_nation_crest:
|
|
for value in self.instance_nation_crest:
|
|
stream.write_long(value)
|
|
stream.write_bool(self.instance_is_descriptor)
|
|
|
|
def save_json(self):
|
|
data = OrderedDict()
|
|
data['instance_template_id'] = self.instance_template_id
|
|
data['instance_id'] = self.instance_id
|
|
data['instance_location'] = self.instance_location
|
|
data['instance_scale'] = self.instance_scale
|
|
data['instance_orientation'] = self.instance_orientation
|
|
data['instance_container_id'] = self.instance_container_id
|
|
data['instance_level_number'] = self.instance_level_number
|
|
data['instance_room_number'] = self.instance_room_number
|
|
data['instance_color'] = self.instance_color
|
|
data['instance_gravity'] = self.instance_gravity
|
|
data['instance_name_override'] = self.instance_name_override
|
|
data['instance_has_health'] = self.instance_has_health
|
|
if self.instance_has_health:
|
|
data['instance_health_full'] = self.instance_health_full
|
|
data['instance_health_current'] = self.instance_health_current
|
|
data['instance_has_item_data'] = self.instance_has_item_data
|
|
if self.instance_has_item_data:
|
|
data['instance_maker_id'] = self.instance_maker_id
|
|
data['instance_value'] = self.instance_value
|
|
data['instance_mod_value'] = self.instance_mod_value
|
|
data['instance_drop_chance'] = self.instance_drop_chance
|
|
data['instance_flags'] = self.instance_flags
|
|
data['instance_charges'] = self.instance_charges
|
|
data['instance_power_actions'] = [action.save_json() for action in self.instance_power_actions]
|
|
data['instance_stack_count'] = self.instance_stack_count
|
|
data['instance_has_key_data'] = self.instance_has_key_data
|
|
if self.instance_has_key_data:
|
|
data['instance_key_ids'] = self.instance_key_ids
|
|
data['instance_key_setting'] = self.instance_key_setting
|
|
data['instance_has_deed_data'] = self.instance_has_deed_data
|
|
if self.instance_has_deed_data:
|
|
data['instance_deed_id'] = self.instance_deed_id
|
|
data['instance_deed_rank'] = self.instance_deed_rank
|
|
data['instance_has_platform_data'] = self.instance_has_platform_data
|
|
if self.instance_has_platform_data:
|
|
data['instance_has_platform'] = self.instance_has_platform
|
|
data['instance_platform_height'] = self.instance_platform_height
|
|
data['instance_damage_flags'] = self.instance_damage_flags
|
|
data['instance_map_type'] = self.instance_map_type
|
|
data['instance_has_guild_crest'] = self.instance_has_guild_crest
|
|
if self.instance_has_guild_crest:
|
|
data['instance_guild_crest'] = self.instance_guild_crest
|
|
data['instance_has_nation_crest'] = self.instance_has_nation_crest
|
|
if self.instance_has_nation_crest:
|
|
data['instance_nation_crest'] = self.instance_nation_crest
|
|
data['instance_is_descriptor'] = self.instance_is_descriptor
|
|
return data
|
|
|
|
def load_json(self, data):
|
|
self.instance_template_id = data['instance_template_id']
|
|
self.instance_id = data['instance_id']
|
|
self.instance_location = data['instance_location']
|
|
self.instance_scale = data['instance_scale']
|
|
self.instance_orientation = data['instance_orientation']
|
|
self.instance_container_id = data['instance_container_id']
|
|
self.instance_level_number = data['instance_level_number']
|
|
self.instance_room_number = data['instance_room_number']
|
|
self.instance_color = data['instance_color']
|
|
self.instance_gravity = data['instance_gravity']
|
|
self.instance_name_override = data['instance_name_override']
|
|
self.instance_has_health = data['instance_has_health']
|
|
if self.instance_has_health:
|
|
self.instance_health_full = data['instance_health_full']
|
|
self.instance_health_current = data['instance_health_current']
|
|
self.instance_has_item_data = data['instance_has_item_data']
|
|
if self.instance_has_item_data:
|
|
self.instance_maker_id = data['instance_maker_id']
|
|
self.instance_value = data['instance_value']
|
|
self.instance_mod_value = data['instance_mod_value']
|
|
self.instance_drop_chance = data['instance_drop_chance']
|
|
self.instance_flags = data['instance_flags']
|
|
self.instance_charges = data['instance_charges']
|
|
self.instance_power_actions = []
|
|
for action_data in data['instance_power_actions']:
|
|
action = PowerActionInfo()
|
|
action.load_json(action_data)
|
|
self.instance_power_actions.append(action)
|
|
self.instance_stack_count = data['instance_stack_count']
|
|
self.instance_has_key_data = data['instance_has_key_data']
|
|
if self.instance_has_key_data:
|
|
self.instance_key_ids = data['instance_key_ids']
|
|
self.instance_key_setting = data['instance_key_setting']
|
|
self.instance_has_deed_data = data['instance_has_deed_data']
|
|
if self.instance_has_deed_data:
|
|
self.instance_deed_id = data['instance_deed_id']
|
|
self.instance_deed_rank = data['instance_deed_rank']
|
|
self.instance_has_platform_data = data['instance_has_platform_data']
|
|
if self.instance_has_platform_data:
|
|
self.instance_has_platform = data['instance_has_platform']
|
|
self.instance_platform_height = data['instance_platform_height']
|
|
self.instance_damage_flags = data['instance_damage_flags']
|
|
self.instance_map_type = data['instance_map_type']
|
|
self.instance_has_guild_crest = data['instance_has_guild_crest']
|
|
if self.instance_has_guild_crest:
|
|
self.instance_guild_crest = data['instance_guild_crest']
|
|
self.instance_has_nation_crest = data['instance_has_nation_crest']
|
|
if self.instance_has_nation_crest:
|
|
self.instance_nation_crest = data['instance_nation_crest']
|
|
self.instance_is_descriptor = data['instance_is_descriptor']
|