mbEditorPro2.0 release
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from PIL import Image, ImageOps
|
||||
|
||||
from arcane.util import ResStream
|
||||
|
||||
|
||||
class ArcTexture:
|
||||
VALUE_TO_MODE = {
|
||||
(4, 8, 2): 'RGBA',
|
||||
(3, 0, 0): 'RGB',
|
||||
(1, 0, 0): 'L',
|
||||
(1, 8, 2): 'P',
|
||||
}
|
||||
|
||||
MODE_TO_VALUE = {value: key for key, value in VALUE_TO_MODE.items()}
|
||||
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.image_width = stream.read_dword()
|
||||
self.image_height = stream.read_dword()
|
||||
self.image_color_depth = stream.read_dword()
|
||||
self.image_alpha = stream.read_dword()
|
||||
self.image_type = stream.read_dword()
|
||||
self.image_compressed = stream.read_bool()
|
||||
self.image_linear = stream.read_bool()
|
||||
data_size = stream.read_dword()
|
||||
self.image_data = stream.read_bytes(data_size)
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.image_width)
|
||||
stream.write_dword(self.image_height)
|
||||
stream.write_dword(self.image_color_depth)
|
||||
stream.write_dword(self.image_alpha)
|
||||
stream.write_dword(self.image_type)
|
||||
stream.write_bool(self.image_compressed)
|
||||
stream.write_bool(self.image_linear)
|
||||
stream.write_dword(len(self.image_data))
|
||||
stream.write_bytes(self.image_data)
|
||||
|
||||
def load_img(self, filepath):
|
||||
img = Image.open(filepath)
|
||||
img = ImageOps.mirror(img).rotate(180)
|
||||
self.image_width = img.width
|
||||
self.image_height = img.height
|
||||
self.image_color_depth, self.image_alpha, self.image_type = self.MODE_TO_VALUE[img.mode]
|
||||
self.image_compressed = True
|
||||
self.image_linear = True
|
||||
self.image_data = img.tobytes()
|
||||
|
||||
def save_img(self, filepath):
|
||||
mode = self.VALUE_TO_MODE[
|
||||
(self.image_color_depth, self.image_alpha, self.image_type)
|
||||
]
|
||||
img = Image.frombytes(mode, (self.image_width, self.image_height), self.image_data)
|
||||
img = ImageOps.mirror(img.rotate(180))
|
||||
img.save(filepath)
|
||||
|
||||
|
||||
class ArcTerrain(ArcTexture):
|
||||
VALUE_TO_MODE = {
|
||||
(1, 1, 0): 'P',
|
||||
}
|
||||
|
||||
MODE_TO_VALUE = {value: key for key, value in VALUE_TO_MODE.items()}
|
||||
@@ -0,0 +1,113 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.util import ResStream
|
||||
|
||||
|
||||
class ArcMesh:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.mesh_name = stream.read_string()
|
||||
self.mesh_distance = stream.read_float()
|
||||
self.mesh_start_point = stream.read_tuple()
|
||||
self.mesh_end_point = stream.read_tuple()
|
||||
self.mesh_ref_point = stream.read_tuple()
|
||||
self.mesh_use_face_normals = stream.read_bool()
|
||||
self.mesh_use_tangent_basis = stream.read_bool()
|
||||
num_vertices = stream.read_dword()
|
||||
self.mesh_vertices = [stream.read_tuple() for _ in range(num_vertices)]
|
||||
num_other_vertices = stream.read_dword()
|
||||
self.mesh_normals = [stream.read_tuple() for _ in range(num_other_vertices)]
|
||||
num = stream.read_dword()
|
||||
self.mesh_uv = [
|
||||
[
|
||||
stream.read_float(),
|
||||
stream.read_float(),
|
||||
] for _ in range(num)
|
||||
]
|
||||
if self.mesh_use_tangent_basis:
|
||||
num_tangent_vertices = stream.read_dword()
|
||||
self.mesh_tanget_vertices = [stream.read_tuple() for _ in range(num_tangent_vertices)]
|
||||
num_indicies = stream.read_dword()
|
||||
self.mesh_indices = [stream.read_word() for _ in range(num_indicies)]
|
||||
num = stream.read_dword()
|
||||
self.mesh_extra_indices = [
|
||||
[
|
||||
stream.read_dword(),
|
||||
stream.read_dword(),
|
||||
[stream.read_word() for _ in range(stream.read_dword())],
|
||||
] for _ in range(num)
|
||||
]
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_string(self.mesh_name)
|
||||
stream.write_float(self.mesh_distance)
|
||||
stream.write_tuple(self.mesh_start_point)
|
||||
stream.write_tuple(self.mesh_end_point)
|
||||
stream.write_tuple(self.mesh_ref_point)
|
||||
stream.write_bool(self.mesh_use_face_normals)
|
||||
stream.write_bool(self.mesh_use_tangent_basis)
|
||||
stream.write_dword(len(self.mesh_vertices))
|
||||
for i in range(len(self.mesh_vertices)):
|
||||
stream.write_tuple(self.mesh_vertices[i])
|
||||
stream.write_dword(len(self.mesh_normals))
|
||||
for i in range(len(self.mesh_normals)):
|
||||
stream.write_tuple(self.mesh_normals[i])
|
||||
stream.write_dword(len(self.mesh_uv))
|
||||
for i in range(len(self.mesh_uv)):
|
||||
stream.write_float(self.mesh_uv[i][0])
|
||||
stream.write_float(self.mesh_uv[i][1])
|
||||
if self.mesh_use_tangent_basis:
|
||||
stream.write_dword(len(self.mesh_tanget_vertices))
|
||||
for i in range(len(self.mesh_tanget_vertices)):
|
||||
stream.write_tuple(self.mesh_tanget_vertices[i])
|
||||
stream.write_dword(len(self.mesh_indices))
|
||||
for i in range(len(self.mesh_indices)):
|
||||
stream.write_word(self.mesh_indices[i])
|
||||
stream.write_dword(len(self.mesh_extra_indices))
|
||||
for i in range(len(self.mesh_extra_indices)):
|
||||
stream.write_dword(self.mesh_extra_indices[i][0])
|
||||
stream.write_dword(self.mesh_extra_indices[i][1])
|
||||
stream.write_dword(len(self.mesh_extra_indices[i][2]))
|
||||
for j in range(len(self.mesh_extra_indices[i][2])):
|
||||
stream.write_word(self.mesh_extra_indices[i][2][j])
|
||||
|
||||
def load_json(self, data):
|
||||
self.mesh_name = data['mesh_name']
|
||||
self.mesh_distance = data['mesh_distance']
|
||||
self.mesh_start_point = data['mesh_start_point']
|
||||
self.mesh_end_point = data['mesh_end_point']
|
||||
self.mesh_ref_point = data['mesh_ref_point']
|
||||
self.mesh_use_face_normals = data['mesh_use_face_normals']
|
||||
self.mesh_use_tangent_basis = data['mesh_use_tangent_basis']
|
||||
self.mesh_vertices = data['mesh_vertices']
|
||||
self.mesh_normals = data['mesh_normals']
|
||||
self.mesh_uv = data['mesh_uv']
|
||||
if self.mesh_use_tangent_basis:
|
||||
self.mesh_tanget_vertices = data['mesh_tanget_vertices']
|
||||
self.mesh_indices = data['mesh_indices']
|
||||
self.mesh_extra_indices = data['mesh_extra_indices']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['mesh_name'] = self.mesh_name
|
||||
data['mesh_distance'] = self.mesh_distance
|
||||
data['mesh_start_point'] = self.mesh_start_point
|
||||
data['mesh_end_point'] = self.mesh_end_point
|
||||
data['mesh_ref_point'] = self.mesh_ref_point
|
||||
data['mesh_use_face_normals'] = self.mesh_use_face_normals
|
||||
data['mesh_use_tangent_basis'] = self.mesh_use_tangent_basis
|
||||
data['mesh_vertices'] = self.mesh_vertices
|
||||
data['mesh_normals'] = self.mesh_normals
|
||||
data['mesh_uv'] = self.mesh_uv
|
||||
if self.mesh_use_tangent_basis:
|
||||
data['mesh_tanget_vertices'] = self.mesh_tanget_vertices
|
||||
data['mesh_indices'] = self.mesh_indices
|
||||
data['mesh_extra_indices'] = self.mesh_extra_indices
|
||||
return data
|
||||
@@ -0,0 +1,89 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.util import ResStream
|
||||
|
||||
|
||||
class ArcMotion:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.motion_file = stream.read_string()
|
||||
self.motion_smoothed_count = stream.read_dword()
|
||||
self.motion_smoothed_value = stream.read_dword()
|
||||
self.motion_smoothed_factor = stream.read_float()
|
||||
self.motion_sound = stream.read_qword()
|
||||
self.motion_sheath = stream.read_dword()
|
||||
self.motion_reset_loc = stream.read_bool()
|
||||
self.motion_leave_ground = stream.read_bool()
|
||||
self.motion_force = stream.read_float()
|
||||
self.motion_disable_blend = stream.read_bool()
|
||||
num_parts = stream.read_dword()
|
||||
self.motion_parts = [stream.read_string() for _ in range(num_parts)]
|
||||
num_smoothing = stream.read_dword()
|
||||
self.motion_smoothing = [
|
||||
[
|
||||
stream.read_float() for _ in range(10)
|
||||
] for _ in range(num_smoothing)
|
||||
]
|
||||
num_target_frames = stream.read_dword()
|
||||
self.motion_target_frames = [stream.read_dword() for _ in range(num_target_frames)]
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_string(self.motion_file)
|
||||
stream.write_dword(self.motion_smoothed_count)
|
||||
stream.write_dword(self.motion_smoothed_value)
|
||||
stream.write_float(self.motion_smoothed_factor)
|
||||
stream.write_qword(self.motion_sound)
|
||||
stream.write_dword(self.motion_sheath)
|
||||
stream.write_bool(self.motion_reset_loc)
|
||||
stream.write_bool(self.motion_leave_ground)
|
||||
stream.write_float(self.motion_force)
|
||||
stream.write_bool(self.motion_disable_blend)
|
||||
stream.write_dword(len(self.motion_parts))
|
||||
for i in range(len(self.motion_parts)):
|
||||
stream.write_string(self.motion_parts[i])
|
||||
stream.write_dword(len(self.motion_smoothing))
|
||||
for i in range(len(self.motion_smoothing)):
|
||||
for j in range(10):
|
||||
stream.write_float(self.motion_smoothing[i][j])
|
||||
stream.write_dword(len(self.motion_target_frames))
|
||||
for i in range(len(self.motion_target_frames)):
|
||||
stream.write_dword(self.motion_target_frames[i])
|
||||
|
||||
def load_json(self, data):
|
||||
self.motion_file = data['motion_file']
|
||||
self.motion_smoothed_count = data['motion_smoothed_count']
|
||||
self.motion_smoothed_value = data['motion_smoothed_value']
|
||||
self.motion_smoothed_factor = data['motion_smoothed_factor']
|
||||
self.motion_sound = data['motion_sound']
|
||||
self.motion_sheath = data['motion_sheath']
|
||||
self.motion_reset_loc = data['motion_reset_loc']
|
||||
self.motion_leave_ground = data['motion_leave_ground']
|
||||
self.motion_force = data['motion_force']
|
||||
self.motion_disable_blend = data['motion_disable_blend']
|
||||
self.motion_parts = data['motion_parts']
|
||||
self.motion_smoothing = data['motion_smoothing']
|
||||
self.motion_target_frames = data['motion_target_frames']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['motion_file'] = self.motion_file
|
||||
data['motion_smoothed_count'] = self.motion_smoothed_count
|
||||
data['motion_smoothed_value'] = self.motion_smoothed_value
|
||||
data['motion_smoothed_factor'] = self.motion_smoothed_factor
|
||||
data['motion_sound'] = self.motion_sound
|
||||
data['motion_sheath'] = self.motion_sheath
|
||||
data['motion_reset_loc'] = self.motion_reset_loc
|
||||
data['motion_leave_ground'] = self.motion_leave_ground
|
||||
data['motion_force'] = self.motion_force
|
||||
data['motion_disable_blend'] = self.motion_disable_blend
|
||||
data['motion_parts'] = self.motion_parts
|
||||
data['motion_smoothing'] = self.motion_smoothing
|
||||
data['motion_target_frames'] = self.motion_target_frames
|
||||
return data
|
||||
@@ -0,0 +1,644 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.util import ResStream
|
||||
|
||||
TRACKER_TO_STRING = {
|
||||
0: 'NONE',
|
||||
1: 'XY',
|
||||
2: 'Y',
|
||||
}
|
||||
STRING_TO_TRACKER = {value: key for key, value in TRACKER_TO_STRING.items()}
|
||||
|
||||
TRANSPARENT_TO_STRING = {
|
||||
0: 'NONE',
|
||||
1: 'PINK',
|
||||
2: 'BLACK',
|
||||
3: 'WHITE',
|
||||
4: 'SEMI',
|
||||
6: 'ALPHA',
|
||||
}
|
||||
STRING_TO_TRANSPARENT = {value: key for key, value in TRANSPARENT_TO_STRING.items()}
|
||||
|
||||
TEXTURE_TO_STRING = {
|
||||
0: 'SINGLE_TEXTURE',
|
||||
1: 'COLOR_TEXTURE',
|
||||
3: 'ANIMATED_TEXTURE',
|
||||
}
|
||||
STRING_TO_TEXTURE = {value: key for key, value in TEXTURE_TO_STRING.items()}
|
||||
|
||||
LIGHT_TYPE_TO_STRING = {
|
||||
0xb6787258: 'ArcLightPoint',
|
||||
0x54e8ff1d: 'ArcLightAffectorAttach',
|
||||
0xa73bd9d4: 'ArcLightAffectorFlicker',
|
||||
}
|
||||
STRING_TO_LIGHT_TYPE = {value: key for key, value in LIGHT_TYPE_TO_STRING.items()}
|
||||
|
||||
|
||||
class ArcSinglePolyMesh:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.polymesh_id = stream.read_qword()
|
||||
self.polymesh_decal = stream.read_bool()
|
||||
self.polymesh_double_sided = stream.read_bool()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_qword(self.polymesh_id)
|
||||
stream.write_bool(self.polymesh_decal)
|
||||
stream.write_bool(self.polymesh_double_sided)
|
||||
|
||||
def load_json(self, data):
|
||||
self.polymesh_id = data['polymesh_id']
|
||||
self.polymesh_decal = data['polymesh_decal']
|
||||
self.polymesh_double_sided = data['polymesh_double_sided']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['polymesh_id'] = self.polymesh_id
|
||||
data['polymesh_decal'] = self.polymesh_decal
|
||||
data['polymesh_double_sided'] = self.polymesh_double_sided
|
||||
return data
|
||||
|
||||
|
||||
class ArcMeshSet:
|
||||
def load_binary(self, stream: ResStream):
|
||||
num = stream.read_dword()
|
||||
self.mesh_set = [ArcSinglePolyMesh() for _ in range(num)]
|
||||
for mesh in self.mesh_set:
|
||||
mesh.load_binary(stream)
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(len(self.mesh_set))
|
||||
for mesh in self.mesh_set:
|
||||
mesh.save_binary(stream)
|
||||
|
||||
def load_json(self, data):
|
||||
self.mesh_set = []
|
||||
for mesh_data in data['mesh_set']:
|
||||
mesh = ArcSinglePolyMesh()
|
||||
mesh.load_json(mesh_data)
|
||||
self.mesh_set.append(mesh)
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['mesh_set'] = []
|
||||
for mesh in self.mesh_set:
|
||||
data['mesh_set'].append(mesh.save_json())
|
||||
return data
|
||||
|
||||
|
||||
class ArcRenderTemplate:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.template_object_can_fade = stream.read_bool()
|
||||
self.template_tracker = stream.read_dword()
|
||||
self.template_illuminated = stream.read_bool()
|
||||
self.template_bone_length = stream.read_float()
|
||||
self.template_clip_map = stream.read_dword()
|
||||
self.template_light_two_side = stream.read_dword()
|
||||
self.template_cull_face = stream.read_dword()
|
||||
self.template_specular_map = stream.read_qword()
|
||||
self.template_shininess = stream.read_float()
|
||||
self.template_has_mesh = stream.read_bool()
|
||||
if self.template_has_mesh:
|
||||
self.template_mesh = ArcMeshSet()
|
||||
self.template_mesh.load_binary(stream)
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_bool(self.template_object_can_fade)
|
||||
stream.write_dword(self.template_tracker)
|
||||
stream.write_bool(self.template_illuminated)
|
||||
stream.write_float(self.template_bone_length)
|
||||
stream.write_dword(self.template_clip_map)
|
||||
stream.write_dword(self.template_light_two_side)
|
||||
stream.write_dword(self.template_cull_face)
|
||||
stream.write_qword(self.template_specular_map)
|
||||
stream.write_float(self.template_shininess)
|
||||
stream.write_bool(self.template_has_mesh)
|
||||
if self.template_has_mesh:
|
||||
self.template_mesh.save_binary(stream)
|
||||
|
||||
def load_json(self, data):
|
||||
self.template_object_can_fade = data['template_object_can_fade']
|
||||
self.template_tracker = STRING_TO_TRACKER[data['template_tracker']]
|
||||
self.template_illuminated = data['template_illuminated']
|
||||
self.template_bone_length = data['template_bone_length']
|
||||
self.template_clip_map = data['template_clip_map']
|
||||
self.template_light_two_side = data['template_light_two_side']
|
||||
self.template_cull_face = data['template_cull_face']
|
||||
self.template_specular_map = data['template_specular_map']
|
||||
self.template_shininess = data['template_shininess']
|
||||
self.template_has_mesh = data['template_has_mesh']
|
||||
if self.template_has_mesh:
|
||||
self.template_mesh = ArcMeshSet()
|
||||
self.template_mesh.load_json(data['template_mesh'])
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['template_object_can_fade'] = self.template_object_can_fade
|
||||
data['template_tracker'] = TRACKER_TO_STRING[self.template_tracker]
|
||||
data['template_illuminated'] = self.template_illuminated
|
||||
data['template_bone_length'] = self.template_bone_length
|
||||
data['template_clip_map'] = self.template_clip_map
|
||||
data['template_light_two_side'] = self.template_light_two_side
|
||||
data['template_cull_face'] = self.template_cull_face
|
||||
data['template_specular_map'] = self.template_specular_map
|
||||
data['template_shininess'] = self.template_shininess
|
||||
data['template_has_mesh'] = self.template_has_mesh
|
||||
if self.template_has_mesh:
|
||||
data['template_mesh'] = self.template_mesh.save_json()
|
||||
return data
|
||||
|
||||
|
||||
class ArcSingleTexture:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.texture_id = stream.read_qword()
|
||||
self.texture_transparent = stream.read_dword()
|
||||
self.texture_compress = stream.read_bool()
|
||||
self.texture_normal_map = stream.read_bool()
|
||||
self.texture_detail_normal_map = stream.read_bool()
|
||||
self.texture_create_mip_maps = stream.read_bool()
|
||||
self.texture_x0 = stream.read_string()
|
||||
self.texture_x1 = stream.read_string()
|
||||
self.texture_x2 = stream.read_dword()
|
||||
self.texture_x3 = stream.read_dword()
|
||||
self.texture_x4 = stream.read_bool()
|
||||
self.texture_wrap = stream.read_bool()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_qword(self.texture_id)
|
||||
stream.write_dword(self.texture_transparent)
|
||||
stream.write_bool(self.texture_compress)
|
||||
stream.write_bool(self.texture_normal_map)
|
||||
stream.write_bool(self.texture_detail_normal_map)
|
||||
stream.write_bool(self.texture_create_mip_maps)
|
||||
stream.write_string(self.texture_x0)
|
||||
stream.write_string(self.texture_x1)
|
||||
stream.write_dword(self.texture_x2)
|
||||
stream.write_dword(self.texture_x3)
|
||||
stream.write_bool(self.texture_x4)
|
||||
stream.write_bool(self.texture_wrap)
|
||||
|
||||
def load_json(self, data):
|
||||
self.texture_id = data['texture_id']
|
||||
self.texture_transparent = STRING_TO_TRANSPARENT[data['texture_transparent']]
|
||||
self.texture_compress = data['texture_compress']
|
||||
self.texture_normal_map = data['texture_normal_map']
|
||||
self.texture_detail_normal_map = data['texture_detail_normal_map']
|
||||
self.texture_create_mip_maps = data['texture_create_mip_maps']
|
||||
self.texture_x0 = ''
|
||||
self.texture_x1 = ''
|
||||
self.texture_x2 = 255
|
||||
self.texture_x3 = 0
|
||||
self.texture_x4 = False
|
||||
self.texture_wrap = data['texture_wrap']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['texture_id'] = self.texture_id
|
||||
data['texture_transparent'] = TRANSPARENT_TO_STRING[self.texture_transparent]
|
||||
data['texture_compress'] = self.texture_compress
|
||||
data['texture_normal_map'] = self.texture_normal_map
|
||||
data['texture_detail_normal_map'] = self.texture_detail_normal_map
|
||||
data['texture_create_mip_maps'] = self.texture_create_mip_maps
|
||||
data['texture_wrap'] = self.texture_wrap
|
||||
return data
|
||||
|
||||
|
||||
class ArcColorTexture(ArcSingleTexture):
|
||||
pass
|
||||
|
||||
|
||||
class ArcAnimatedTexture:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.animated_texture_id = stream.read_qword()
|
||||
self.animated_texture_transparent = stream.read_dword()
|
||||
self.animated_texture_compress = stream.read_bool()
|
||||
self.animated_texture_normal_map = stream.read_bool()
|
||||
self.animated_texture_detail_normal_map = stream.read_bool()
|
||||
self.animated_texture_create_mip_maps = stream.read_bool()
|
||||
self.animated_texture_frame_timer = stream.read_float()
|
||||
self.animated_texture_x0 = stream.read_float()
|
||||
self.animated_texture_frame_rand = stream.read_dword()
|
||||
|
||||
num = stream.read_dword()
|
||||
self.animated_texture_sets = [ArcTextureSet() for _ in range(num)]
|
||||
for texture in self.animated_texture_sets:
|
||||
texture.load_binary(stream)
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_qword(self.animated_texture_id)
|
||||
stream.write_dword(self.animated_texture_transparent)
|
||||
stream.write_bool(self.animated_texture_compress)
|
||||
stream.write_bool(self.animated_texture_normal_map)
|
||||
stream.write_bool(self.animated_texture_detail_normal_map)
|
||||
stream.write_bool(self.animated_texture_create_mip_maps)
|
||||
stream.write_float(self.animated_texture_frame_timer)
|
||||
stream.write_float(self.animated_texture_x0)
|
||||
stream.write_dword(self.animated_texture_frame_rand)
|
||||
|
||||
stream.write_dword(len(self.animated_texture_sets))
|
||||
for texture in self.animated_texture_sets:
|
||||
texture.save_binary(stream)
|
||||
|
||||
def load_json(self, data):
|
||||
self.animated_texture_id = data['animated_texture_id']
|
||||
self.animated_texture_transparent = STRING_TO_TRANSPARENT[data['animated_texture_transparent']]
|
||||
self.animated_texture_compress = data['animated_texture_compress']
|
||||
self.animated_texture_normal_map = data['animated_texture_normal_map']
|
||||
self.animated_texture_detail_normal_map = data['animated_texture_detail_normal_map']
|
||||
self.animated_texture_create_mip_maps = data['animated_texture_create_mip_maps']
|
||||
self.animated_texture_frame_timer = data['animated_texture_frame_timer']
|
||||
self.animated_texture_x0 = 0.0
|
||||
self.animated_texture_frame_rand = data['animated_texture_frame_rand']
|
||||
self.animated_texture_sets = []
|
||||
for texture_data in data['animated_texture_sets']:
|
||||
texture = ArcTextureSet()
|
||||
texture.load_json(texture_data)
|
||||
self.animated_texture_sets.append(texture)
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['animated_texture_id'] = self.animated_texture_id
|
||||
data['animated_texture_transparent'] = TRANSPARENT_TO_STRING[self.animated_texture_transparent]
|
||||
data['animated_texture_compress'] = self.animated_texture_compress
|
||||
data['animated_texture_normal_map'] = self.animated_texture_normal_map
|
||||
data['animated_texture_detail_normal_map'] = self.animated_texture_detail_normal_map
|
||||
data['animated_texture_create_mip_maps'] = self.animated_texture_create_mip_maps
|
||||
data['animated_texture_frame_timer'] = self.animated_texture_frame_timer
|
||||
data['animated_texture_frame_rand'] = self.animated_texture_frame_rand
|
||||
data['animated_texture_sets'] = []
|
||||
for texture in self.animated_texture_sets:
|
||||
data['animated_texture_sets'].append(texture.save_json())
|
||||
return data
|
||||
|
||||
|
||||
class ArcTextureSet:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.texture_type = stream.read_dword()
|
||||
if self.texture_type == 0:
|
||||
self.texture_data = ArcSingleTexture()
|
||||
elif self.texture_type == 1:
|
||||
self.texture_data = ArcColorTexture()
|
||||
elif self.texture_type == 3:
|
||||
self.texture_data = ArcAnimatedTexture()
|
||||
self.texture_data.load_binary(stream)
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.texture_type)
|
||||
self.texture_data.save_binary(stream)
|
||||
|
||||
def load_json(self, data):
|
||||
self.texture_type = STRING_TO_TEXTURE[data['texture_type']]
|
||||
if self.texture_type == 0:
|
||||
self.texture_data = ArcSingleTexture()
|
||||
elif self.texture_type == 1:
|
||||
self.texture_data = ArcColorTexture()
|
||||
elif self.texture_type == 3:
|
||||
self.texture_data = ArcAnimatedTexture()
|
||||
self.texture_data.load_json(data['texture_data'])
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['texture_type'] = TEXTURE_TO_STRING[self.texture_type]
|
||||
data['texture_data'] = self.texture_data.save_json()
|
||||
return data
|
||||
|
||||
|
||||
class ArcLightPoint:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.lightpoint_x0 = stream.read_dword()
|
||||
self.lightpoint_x1 = stream.read_bool()
|
||||
self.lightpoint_shader = stream.read_bool()
|
||||
self.lightpoint_update_offscreen = stream.read_bool()
|
||||
self.lightpoint_radius = stream.read_float()
|
||||
self.lightpoint_position = stream.read_tuple()
|
||||
self.lightpoint_diffuse_color = [stream.read_float() for _ in range(4)]
|
||||
self.lightpoint_x2 = stream.read_dword()
|
||||
self.lightpoint_orientation = [stream.read_float() for _ in range(4)]
|
||||
self.lightpoint_cubemap = stream.read_dword()
|
||||
self.lightpoint_x3 = stream.read_bool()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.lightpoint_x0)
|
||||
stream.write_bool(self.lightpoint_x1)
|
||||
stream.write_bool(self.lightpoint_shader)
|
||||
stream.write_bool(self.lightpoint_update_offscreen)
|
||||
stream.write_float(self.lightpoint_radius)
|
||||
stream.write_tuple(self.lightpoint_position)
|
||||
for i in range(4):
|
||||
stream.write_float(self.lightpoint_diffuse_color[i])
|
||||
stream.write_dword(self.lightpoint_x2)
|
||||
for i in range(4):
|
||||
stream.write_float(self.lightpoint_orientation[i])
|
||||
stream.write_dword(self.lightpoint_cubemap)
|
||||
stream.write_bool(self.lightpoint_x3)
|
||||
|
||||
def load_json(self, data):
|
||||
self.lightpoint_x0 = 1
|
||||
self.lightpoint_x1 = True
|
||||
self.lightpoint_shader = data['lightpoint_shader']
|
||||
self.lightpoint_update_offscreen = data['lightpoint_update_offscreen']
|
||||
self.lightpoint_radius = data['lightpoint_radius']
|
||||
self.lightpoint_position = data['lightpoint_position']
|
||||
self.lightpoint_diffuse_color = data['lightpoint_diffuse_color']
|
||||
self.lightpoint_x2 = 1
|
||||
self.lightpoint_orientation = data['lightpoint_orientation']
|
||||
self.lightpoint_cubemap = data['lightpoint_cubemap']
|
||||
self.lightpoint_x3 = False
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['lightpoint_shader'] = self.lightpoint_shader
|
||||
data['lightpoint_update_offscreen'] = self.lightpoint_update_offscreen
|
||||
data['lightpoint_radius'] = self.lightpoint_radius
|
||||
data['lightpoint_position'] = self.lightpoint_position
|
||||
data['lightpoint_diffuse_color'] = self.lightpoint_diffuse_color
|
||||
data['lightpoint_orientation'] = self.lightpoint_orientation
|
||||
data['lightpoint_cubemap'] = self.lightpoint_cubemap
|
||||
return data
|
||||
|
||||
|
||||
class ArcLightAffectorAttach:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.attach_x0 = stream.read_dword()
|
||||
self.attach_offset = stream.read_tuple()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.attach_x0)
|
||||
stream.write_tuple(self.attach_offset)
|
||||
|
||||
def load_json(self, data):
|
||||
self.attach_x0 = 1
|
||||
self.attach_offset = data['attach_offset']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['attach_offset'] = self.attach_offset
|
||||
return data
|
||||
|
||||
|
||||
class ArcLightAffectorFlicker:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.flicker_x0 = stream.read_dword()
|
||||
self.flicker_avg_period = stream.read_float()
|
||||
self.flicker_std_dev_radius = stream.read_float()
|
||||
self.flicker_std_dev_period = stream.read_float()
|
||||
self.flicker_falloff = stream.read_float()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.flicker_x0)
|
||||
stream.write_float(self.flicker_avg_period)
|
||||
stream.write_float(self.flicker_std_dev_radius)
|
||||
stream.write_float(self.flicker_std_dev_period)
|
||||
stream.write_float(self.flicker_falloff)
|
||||
|
||||
def load_json(self, data):
|
||||
self.flicker_x0 = 1
|
||||
self.flicker_avg_period = data['flicker_avg_period']
|
||||
self.flicker_std_dev_radius = data['flicker_std_dev_radius']
|
||||
self.flicker_std_dev_period = data['flicker_std_dev_period']
|
||||
self.flicker_falloff = data['flicker_falloff']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['flicker_avg_period'] = self.flicker_avg_period
|
||||
data['flicker_std_dev_radius'] = self.flicker_std_dev_radius
|
||||
data['flicker_std_dev_period'] = self.flicker_std_dev_period
|
||||
data['flicker_falloff'] = self.flicker_falloff
|
||||
return data
|
||||
|
||||
|
||||
class ArcLightAffectors:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.light_affector_type = stream.read_dword()
|
||||
|
||||
if self.light_affector_type == 0x54e8ff1d:
|
||||
self.light_affector_data = ArcLightAffectorAttach()
|
||||
elif self.light_affector_type == 0xa73bd9d4:
|
||||
self.light_affector_data = ArcLightAffectorFlicker()
|
||||
self.light_affector_data.load_binary(stream)
|
||||
|
||||
self.light_affector_0xdaed = stream.read_dword()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.light_affector_type)
|
||||
self.light_affector_data.save_binary(stream)
|
||||
stream.write_dword(self.light_affector_0xdaed)
|
||||
|
||||
def load_json(self, data):
|
||||
self.light_affector_type = STRING_TO_LIGHT_TYPE[data['light_affector_type']]
|
||||
if self.light_affector_type == 0x54e8ff1d:
|
||||
self.light_affector_data = ArcLightAffectorAttach()
|
||||
elif self.light_affector_type == 0xa73bd9d4:
|
||||
self.light_affector_data = ArcLightAffectorFlicker()
|
||||
self.light_affector_data.load_json(data['light_affector_data'])
|
||||
self.light_affector_0xdaed = 0xddaaeedd
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['light_affector_type'] = LIGHT_TYPE_TO_STRING[self.light_affector_type]
|
||||
data['light_affector_data'] = self.light_affector_data.save_json()
|
||||
return data
|
||||
|
||||
|
||||
class ArcLight:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.light_x0 = stream.read_dword()
|
||||
self.light_x1 = stream.read_bool()
|
||||
self.light_type = stream.read_dword()
|
||||
|
||||
if self.light_type == 0xb6787258:
|
||||
self.light_data = ArcLightPoint()
|
||||
self.light_data.load_binary(stream)
|
||||
|
||||
self.light_0xdaed = stream.read_dword()
|
||||
|
||||
num = stream.read_dword()
|
||||
self.light_affectors = [ArcLightAffectors() for _ in range(num)]
|
||||
for extra in self.light_affectors:
|
||||
extra.load_binary(stream)
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.light_x0)
|
||||
stream.write_bool(self.light_x1)
|
||||
stream.write_dword(self.light_type)
|
||||
self.light_data.save_binary(stream)
|
||||
stream.write_dword(self.light_0xdaed)
|
||||
|
||||
stream.write_dword(len(self.light_affectors))
|
||||
for extra in self.light_affectors:
|
||||
extra.save_binary(stream)
|
||||
|
||||
def load_json(self, data):
|
||||
self.light_x0 = 1
|
||||
self.light_x1 = True
|
||||
self.light_type = STRING_TO_LIGHT_TYPE[data['light_type']]
|
||||
if self.light_type == 0xb6787258:
|
||||
self.light_data = ArcLightPoint()
|
||||
self.light_data.load_json(data['light_data'])
|
||||
self.light_0xdaed = 0xddaaeedd
|
||||
|
||||
self.light_affectors = []
|
||||
for extra_data in data['light_affectors']:
|
||||
extra = ArcLightAffectors()
|
||||
extra.load_json(extra_data)
|
||||
self.light_affectors.append(extra)
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['light_type'] = LIGHT_TYPE_TO_STRING[self.light_type]
|
||||
data['light_data'] = self.light_data.save_json()
|
||||
|
||||
data['light_affectors'] = []
|
||||
for extra in self.light_affectors:
|
||||
data['light_affectors'].append(extra.save_json())
|
||||
return data
|
||||
|
||||
|
||||
class ArcRender:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.render_template = ArcRenderTemplate()
|
||||
self.render_template.load_binary(stream)
|
||||
self.render_target_bone = stream.read_string()
|
||||
self.render_scale = stream.read_tuple()
|
||||
self.render_has_loc = stream.read_dword()
|
||||
if self.render_has_loc:
|
||||
self.render_loc = stream.read_tuple()
|
||||
num_children = stream.read_dword()
|
||||
self.render_children = [stream.read_qword() for _ in range(num_children)]
|
||||
self.render_has_texture_set = stream.read_bool()
|
||||
if self.render_has_texture_set:
|
||||
num = stream.read_dword()
|
||||
self.render_texture_set = [ArcTextureSet() for _ in range(num)]
|
||||
for texture in self.render_texture_set:
|
||||
texture.load_binary(stream)
|
||||
self.render_collides = stream.read_bool()
|
||||
self.render_calculate_bounding_box = stream.read_bool()
|
||||
self.render_nation_crest = stream.read_bool()
|
||||
self.render_guild_crest = stream.read_bool()
|
||||
self.render_bumped = stream.read_bool()
|
||||
self.render_vp_active = stream.read_bool()
|
||||
if self.render_vp_active:
|
||||
self.render_vp_name = stream.read_string()
|
||||
num_params = stream.read_dword()
|
||||
self.render_vp_params = [
|
||||
[
|
||||
stream.read_dword(),
|
||||
stream.read_float(),
|
||||
stream.read_float(),
|
||||
stream.read_float(),
|
||||
stream.read_float(),
|
||||
] for _ in range(num_params)
|
||||
]
|
||||
self.render_has_light_effects = stream.read_bool()
|
||||
if self.render_has_light_effects:
|
||||
num_effects = stream.read_dword()
|
||||
self.render_light_effects = [ArcLight() for _ in range(num_effects)]
|
||||
for effect in self.render_light_effects:
|
||||
effect.load_binary(stream)
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
self.render_template.save_binary(stream)
|
||||
stream.write_string(self.render_target_bone)
|
||||
stream.write_tuple(self.render_scale)
|
||||
stream.write_dword(self.render_has_loc)
|
||||
if self.render_has_loc:
|
||||
stream.write_tuple(self.render_loc)
|
||||
stream.write_dword(len(self.render_children))
|
||||
for child in self.render_children:
|
||||
stream.write_qword(child)
|
||||
stream.write_bool(self.render_has_texture_set)
|
||||
if self.render_has_texture_set:
|
||||
stream.write_dword(len(self.render_texture_set))
|
||||
for texture in self.render_texture_set:
|
||||
texture.save_binary(stream)
|
||||
stream.write_bool(self.render_collides)
|
||||
stream.write_bool(self.render_calculate_bounding_box)
|
||||
stream.write_bool(self.render_nation_crest)
|
||||
stream.write_bool(self.render_guild_crest)
|
||||
stream.write_bool(self.render_bumped)
|
||||
stream.write_bool(self.render_vp_active)
|
||||
if self.render_vp_active:
|
||||
stream.write_string(self.render_vp_name)
|
||||
|
||||
stream.write_dword(len(self.render_vp_params))
|
||||
for param in self.render_vp_params:
|
||||
stream.write_dword(param[0])
|
||||
stream.write_float(param[1])
|
||||
stream.write_float(param[2])
|
||||
stream.write_float(param[3])
|
||||
stream.write_float(param[4])
|
||||
stream.write_bool(self.render_has_light_effects)
|
||||
if self.render_has_light_effects:
|
||||
stream.write_dword(len(self.render_light_effects))
|
||||
for effect in self.render_light_effects:
|
||||
effect.save_binary(stream)
|
||||
|
||||
def load_json(self, data):
|
||||
self.render_template = ArcRenderTemplate()
|
||||
self.render_template.load_json(data['render_template'])
|
||||
self.render_target_bone = data['render_target_bone']
|
||||
self.render_scale = data['render_scale']
|
||||
self.render_has_loc = data['render_has_loc']
|
||||
if self.render_has_loc:
|
||||
self.render_loc = data['render_loc']
|
||||
self.render_children = data['render_children']
|
||||
self.render_has_texture_set = data['render_has_texture_set']
|
||||
if self.render_has_texture_set:
|
||||
self.render_texture_set = []
|
||||
for texture_data in data['render_texture_set']:
|
||||
texture = ArcTextureSet()
|
||||
texture.load_json(texture_data)
|
||||
self.render_texture_set.append(texture)
|
||||
self.render_collides = data['render_collides']
|
||||
self.render_calculate_bounding_box = data['render_calculate_bounding_box']
|
||||
self.render_nation_crest = data['render_nation_crest']
|
||||
self.render_guild_crest = data['render_guild_crest']
|
||||
self.render_bumped = data['render_bumped']
|
||||
self.render_vp_active = data['render_vp_active']
|
||||
if self.render_vp_active:
|
||||
self.render_vp_name = data['render_vp_name']
|
||||
self.render_vp_params = data['render_vp_params']
|
||||
self.render_has_light_effects = data['render_has_light_effects']
|
||||
if self.render_has_light_effects:
|
||||
self.render_light_effects = []
|
||||
for effect_data in data['render_light_effects']:
|
||||
effect = ArcLight()
|
||||
effect.load_json(effect_data)
|
||||
self.render_light_effects.append(effect)
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['render_template'] = self.render_template.save_json()
|
||||
data['render_target_bone'] = self.render_target_bone
|
||||
data['render_scale'] = self.render_scale
|
||||
data['render_has_loc'] = self.render_has_loc
|
||||
if self.render_has_loc:
|
||||
data['render_loc'] = self.render_loc
|
||||
data['render_children'] = self.render_children
|
||||
data['render_has_texture_set'] = self.render_has_texture_set
|
||||
if self.render_has_texture_set:
|
||||
data['render_texture_set'] = []
|
||||
for texture in self.render_texture_set:
|
||||
data['render_texture_set'].append(texture.save_json())
|
||||
data['render_collides'] = self.render_collides
|
||||
data['render_calculate_bounding_box'] = self.render_calculate_bounding_box
|
||||
data['render_nation_crest'] = self.render_nation_crest
|
||||
data['render_guild_crest'] = self.render_guild_crest
|
||||
data['render_bumped'] = self.render_bumped
|
||||
data['render_vp_active'] = self.render_vp_active
|
||||
if self.render_vp_active:
|
||||
data['render_vp_name'] = self.render_vp_name
|
||||
data['render_vp_params'] = self.render_vp_params
|
||||
data['render_has_light_effects'] = self.render_has_light_effects
|
||||
if self.render_has_light_effects:
|
||||
data['render_light_effects'] = []
|
||||
for effect in self.render_light_effects:
|
||||
data['render_light_effects'].append(effect.save_json())
|
||||
return data
|
||||
@@ -0,0 +1,125 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.util import ResStream
|
||||
|
||||
|
||||
class ArcBone:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.bone_id = stream.read_dword()
|
||||
self.bone_name = stream.read_string()
|
||||
self.bone_direction = stream.read_tuple()
|
||||
self.bone_length = stream.read_float()
|
||||
self.bone_axis = stream.read_tuple()
|
||||
self.bone_dof = stream.read_string()
|
||||
self.bone_order = stream.read_tuple()
|
||||
self.bone_position = stream.read_tuple()
|
||||
self.bone_orientation = stream.read_tuple()
|
||||
self.bone_u0 = stream.read_bool()
|
||||
self.bone_u1 = stream.read_bool()
|
||||
|
||||
num = stream.read_dword()
|
||||
self.bone_hierarchy = [ArcBone() for _ in range(num)]
|
||||
for bone in self.bone_hierarchy:
|
||||
bone.load_binary(stream)
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.bone_id)
|
||||
stream.write_string(self.bone_name)
|
||||
stream.write_tuple(self.bone_direction)
|
||||
stream.write_float(self.bone_length)
|
||||
stream.write_tuple(self.bone_axis)
|
||||
stream.write_string(self.bone_dof)
|
||||
stream.write_tuple(self.bone_order)
|
||||
stream.write_tuple(self.bone_position)
|
||||
stream.write_tuple(self.bone_orientation)
|
||||
stream.write_bool(self.bone_u0)
|
||||
stream.write_bool(self.bone_u1)
|
||||
|
||||
stream.write_dword(len(self.bone_hierarchy))
|
||||
for bone in self.bone_hierarchy:
|
||||
bone.save_binary(stream)
|
||||
|
||||
def load_json(self, data):
|
||||
self.bone_id = data['bone_id']
|
||||
self.bone_name = data['bone_name']
|
||||
self.bone_direction = data['bone_direction']
|
||||
self.bone_length = data['bone_length']
|
||||
self.bone_axis = data['bone_axis']
|
||||
self.bone_dof = data['bone_dof']
|
||||
self.bone_order = data['bone_order']
|
||||
self.bone_position = data['bone_position']
|
||||
self.bone_orientation = data['bone_orientation']
|
||||
self.bone_u0 = data['bone_u0']
|
||||
self.bone_u1 = data['bone_u1']
|
||||
|
||||
self.bone_hierarchy = []
|
||||
for bone_data in data['bone_hierarchy']:
|
||||
bone = ArcBone()
|
||||
bone.load_json(bone_data)
|
||||
self.bone_hierarchy.append(bone)
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['bone_id'] = self.bone_id
|
||||
data['bone_name'] = self.bone_name
|
||||
data['bone_direction'] = self.bone_direction
|
||||
data['bone_length'] = self.bone_length
|
||||
data['bone_axis'] = self.bone_axis
|
||||
data['bone_dof'] = self.bone_dof
|
||||
data['bone_order'] = self.bone_order
|
||||
data['bone_position'] = self.bone_position
|
||||
data['bone_orientation'] = self.bone_orientation
|
||||
data['bone_u0'] = self.bone_u0
|
||||
data['bone_u1'] = self.bone_u1
|
||||
|
||||
data['bone_hierarchy'] = []
|
||||
for bone in self.bone_hierarchy:
|
||||
data['bone_hierarchy'].append(bone.save_json())
|
||||
return data
|
||||
|
||||
|
||||
class ArcSkeleton:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.skeleton_name = stream.read_string()
|
||||
|
||||
num = stream.read_dword()
|
||||
self.skeleton_motion = [
|
||||
[
|
||||
stream.read_qword(),
|
||||
stream.read_qword(),
|
||||
] for _ in range(num)
|
||||
]
|
||||
|
||||
self.skeleton_root = ArcBone()
|
||||
self.skeleton_root.load_binary(stream)
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_string(self.skeleton_name)
|
||||
|
||||
stream.write_dword(len(self.skeleton_motion))
|
||||
for i in range(len(self.skeleton_motion)):
|
||||
stream.write_qword(self.skeleton_motion[i][0])
|
||||
stream.write_qword(self.skeleton_motion[i][1])
|
||||
|
||||
self.skeleton_root.save_binary(stream)
|
||||
|
||||
def load_json(self, data):
|
||||
self.skeleton_name = data['skeleton_name']
|
||||
self.skeleton_motion = data['skeleton_motion']
|
||||
self.skeleton_root = ArcBone()
|
||||
self.skeleton_root.load_json(data['skeleton_root'])
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['skeleton_name'] = self.skeleton_name
|
||||
data['skeleton_motion'] = self.skeleton_motion
|
||||
data['skeleton_root'] = self.skeleton_root.save_json()
|
||||
return data
|
||||
@@ -0,0 +1,40 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from wave import Wave_read, Wave_write
|
||||
|
||||
from arcane.util import ResStream
|
||||
|
||||
|
||||
class ArcSound:
|
||||
def load_binary(self, stream: ResStream):
|
||||
data_size = stream.read_dword()
|
||||
self.sound_frame_rate = stream.read_dword()
|
||||
self.sound_n_channels = stream.read_dword()
|
||||
self.sound_sample_width = stream.read_dword()
|
||||
self.sound_data = stream.read_bytes(data_size)
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
data_size = len(self.sound_data)
|
||||
stream.write_dword(data_size)
|
||||
stream.write_dword(self.sound_frame_rate)
|
||||
stream.write_dword(self.sound_n_channels)
|
||||
stream.write_dword(self.sound_sample_width)
|
||||
stream.write_bytes(self.sound_data)
|
||||
|
||||
def load_wav(self, stream: Wave_read):
|
||||
self.sound_frame_rate = stream.getframerate()
|
||||
self.sound_n_channels = stream.getnchannels()
|
||||
self.sound_sample_width = stream.getsampwidth() * 8
|
||||
self.sound_data = stream.readframes(stream.getnframes())
|
||||
|
||||
def save_wav(self, stream: Wave_write):
|
||||
stream.setframerate(self.sound_frame_rate)
|
||||
stream.setnchannels(self.sound_n_channels)
|
||||
stream.setsampwidth(self.sound_sample_width // 8)
|
||||
stream.writeframes(self.sound_data)
|
||||
@@ -0,0 +1,242 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.util import ResStream
|
||||
|
||||
TILE_TO_STRING = {
|
||||
0: "UNKNOWN",
|
||||
1: "Regular",
|
||||
2: "Slope",
|
||||
3: "Road",
|
||||
}
|
||||
STRING_TO_TILE = {value: key for key, value in TILE_TO_STRING.items()}
|
||||
|
||||
MASK_TO_STRING = {
|
||||
0: "UNKNOWN",
|
||||
1: "Transition",
|
||||
2: "Road",
|
||||
}
|
||||
STRING_TO_MASK = {value: key for key, value in MASK_TO_STRING.items()}
|
||||
|
||||
|
||||
class ArcTile:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.tile_row_0 = stream.read_dword()
|
||||
self.tile_row_1 = stream.read_dword()
|
||||
self.tile_row_2 = stream.read_dword()
|
||||
self.tile_row_3 = stream.read_dword()
|
||||
self.tile_prob = stream.read_float()
|
||||
self.tile_type = stream.read_dword()
|
||||
|
||||
num_alts = stream.read_dword()
|
||||
self.tile_alts = [stream.read_dword() for _ in range(num_alts)]
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.tile_row_0)
|
||||
stream.write_dword(self.tile_row_1)
|
||||
stream.write_dword(self.tile_row_2)
|
||||
stream.write_dword(self.tile_row_3)
|
||||
stream.write_float(self.tile_prob)
|
||||
stream.write_dword(self.tile_type)
|
||||
stream.write_dword(len(self.tile_alts))
|
||||
for i in range(len(self.tile_alts)):
|
||||
stream.write_dword(self.tile_alts[i])
|
||||
|
||||
def load_json(self, data):
|
||||
self.tile_row_0 = data['tile_row_0']
|
||||
self.tile_row_1 = data['tile_row_1']
|
||||
self.tile_row_2 = data['tile_row_2']
|
||||
self.tile_row_3 = data['tile_row_3']
|
||||
self.tile_prob = data['tile_prob']
|
||||
self.tile_type = STRING_TO_TILE[data['tile_type']]
|
||||
self.tile_alts = data['tile_alts']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['tile_row_0'] = self.tile_row_0
|
||||
data['tile_row_1'] = self.tile_row_1
|
||||
data['tile_row_2'] = self.tile_row_2
|
||||
data['tile_row_3'] = self.tile_row_3
|
||||
data['tile_prob'] = self.tile_prob
|
||||
data['tile_type'] = TILE_TO_STRING[self.tile_type]
|
||||
data['tile_alts'] = self.tile_alts
|
||||
return data
|
||||
|
||||
|
||||
class ArcTileMask:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.mask_row_0 = stream.read_dword()
|
||||
self.mask_row_1 = stream.read_dword()
|
||||
self.mask_row_2 = stream.read_dword()
|
||||
self.mask_row_3 = stream.read_dword()
|
||||
self.mask_prob = stream.read_float()
|
||||
self.mask_start = stream.read_dword()
|
||||
self.mask_end = stream.read_dword()
|
||||
self.mask_end1 = stream.read_dword()
|
||||
self.mask_end2 = stream.read_dword()
|
||||
self.mask_type = stream.read_dword()
|
||||
self.mask_width = stream.read_dword()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.mask_row_0)
|
||||
stream.write_dword(self.mask_row_1)
|
||||
stream.write_dword(self.mask_row_2)
|
||||
stream.write_dword(self.mask_row_3)
|
||||
stream.write_float(self.mask_prob)
|
||||
stream.write_dword(self.mask_start)
|
||||
stream.write_dword(self.mask_end)
|
||||
stream.write_dword(self.mask_end1)
|
||||
stream.write_dword(self.mask_end2)
|
||||
stream.write_dword(self.mask_type)
|
||||
stream.write_dword(self.mask_width)
|
||||
|
||||
def load_json(self, data):
|
||||
self.mask_row_0 = data['mask_row_0']
|
||||
self.mask_row_1 = data['mask_row_1']
|
||||
self.mask_row_2 = data['mask_row_2']
|
||||
self.mask_row_3 = data['mask_row_3']
|
||||
self.mask_prob = data['mask_prob']
|
||||
self.mask_start = data['mask_start']
|
||||
self.mask_end = data['mask_end']
|
||||
self.mask_end1 = data['mask_end1']
|
||||
self.mask_end2 = data['mask_end2']
|
||||
self.mask_type = STRING_TO_MASK[data['mask_type']]
|
||||
self.mask_width = data['mask_width']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['mask_row_0'] = self.mask_row_0
|
||||
data['mask_row_1'] = self.mask_row_1
|
||||
data['mask_row_2'] = self.mask_row_2
|
||||
data['mask_row_3'] = self.mask_row_3
|
||||
data['mask_prob'] = self.mask_prob
|
||||
data['mask_start'] = self.mask_start
|
||||
data['mask_end'] = self.mask_end
|
||||
data['mask_end1'] = self.mask_end1
|
||||
data['mask_end2'] = self.mask_end2
|
||||
data['mask_type'] = MASK_TO_STRING[self.mask_type]
|
||||
data['mask_width'] = self.mask_width
|
||||
return data
|
||||
|
||||
|
||||
class ArcTilePattern:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.pattern_row_0 = stream.read_dword()
|
||||
self.pattern_row_1 = stream.read_dword()
|
||||
self.pattern_row_2 = stream.read_dword()
|
||||
self.pattern_row_3 = stream.read_dword()
|
||||
self.pattern_prob = stream.read_float()
|
||||
self.pattern_patx = stream.read_dword()
|
||||
self.pattern_patz = stream.read_dword()
|
||||
num_tiles = stream.read_dword()
|
||||
self.pattern_tiles = [stream.read_dword() for _ in range(num_tiles)]
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.pattern_row_0)
|
||||
stream.write_dword(self.pattern_row_1)
|
||||
stream.write_dword(self.pattern_row_2)
|
||||
stream.write_dword(self.pattern_row_3)
|
||||
stream.write_float(self.pattern_prob)
|
||||
stream.write_dword(self.pattern_patx)
|
||||
stream.write_dword(self.pattern_patz)
|
||||
stream.write_dword(len(self.pattern_tiles))
|
||||
for i in range(len(self.pattern_tiles)):
|
||||
stream.write_dword(self.pattern_tiles[i])
|
||||
|
||||
def load_json(self, data):
|
||||
self.pattern_row_0 = data['pattern_row_0']
|
||||
self.pattern_row_1 = data['pattern_row_1']
|
||||
self.pattern_row_2 = data['pattern_row_2']
|
||||
self.pattern_row_3 = data['pattern_row_3']
|
||||
self.pattern_prob = data['pattern_prob']
|
||||
self.pattern_patx = data['pattern_patx']
|
||||
self.pattern_patz = data['pattern_patz']
|
||||
self.pattern_tiles = data['pattern_tiles']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['pattern_row_0'] = self.pattern_row_0
|
||||
data['pattern_row_1'] = self.pattern_row_1
|
||||
data['pattern_row_2'] = self.pattern_row_2
|
||||
data['pattern_row_3'] = self.pattern_row_3
|
||||
data['pattern_prob'] = self.pattern_prob
|
||||
data['pattern_patx'] = self.pattern_patx
|
||||
data['pattern_patz'] = self.pattern_patz
|
||||
data['pattern_tiles'] = self.pattern_tiles
|
||||
return data
|
||||
|
||||
|
||||
class ArcTileManager:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.manager_texture_width = stream.read_dword()
|
||||
self.manager_tile_width = stream.read_dword()
|
||||
self.manager_tile_texture = stream.read_qword()
|
||||
num_tiles = stream.read_dword()
|
||||
self.manager_tiles = [ArcTile() for _ in range(num_tiles)]
|
||||
for tile in self.manager_tiles:
|
||||
tile.load_binary(stream)
|
||||
num_masks = stream.read_dword()
|
||||
self.manager_masks = [ArcTileMask() for _ in range(num_masks)]
|
||||
for mask in self.manager_masks:
|
||||
mask.load_binary(stream)
|
||||
num_patterns = stream.read_dword()
|
||||
self.manager_patterns = [ArcTilePattern() for _ in range(num_patterns)]
|
||||
for pattern in self.manager_patterns:
|
||||
pattern.load_binary(stream)
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.manager_texture_width)
|
||||
stream.write_dword(self.manager_tile_width)
|
||||
stream.write_qword(self.manager_tile_texture)
|
||||
stream.write_dword(len(self.manager_tiles))
|
||||
for tile in self.manager_tiles:
|
||||
tile.save_binary(stream)
|
||||
stream.write_dword(len(self.manager_masks))
|
||||
for mask in self.manager_masks:
|
||||
mask.save_binary(stream)
|
||||
stream.write_dword(len(self.manager_patterns))
|
||||
for pattern in self.manager_patterns:
|
||||
pattern.save_binary(stream)
|
||||
|
||||
def load_json(self, data):
|
||||
self.manager_texture_width = data['manager_texture_width']
|
||||
self.manager_tile_width = data['manager_tile_width']
|
||||
self.manager_tile_texture = data['manager_tile_texture']
|
||||
self.manager_tiles = []
|
||||
for tile_data in data['manager_tiles']:
|
||||
tile = ArcTile()
|
||||
tile.load_json(tile_data)
|
||||
self.manager_tiles.append(tile)
|
||||
self.manager_masks = []
|
||||
for mask_data in data['manager_masks']:
|
||||
mask = ArcTileMask()
|
||||
mask.load_json(mask_data)
|
||||
self.manager_masks.append(mask)
|
||||
self.manager_patterns = []
|
||||
for pattern_data in data['manager_patterns']:
|
||||
pattern = ArcTilePattern()
|
||||
pattern.load_json(pattern_data)
|
||||
self.manager_patterns.append(pattern)
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['manager_texture_width'] = self.manager_texture_width
|
||||
data['manager_tile_width'] = self.manager_tile_width
|
||||
data['manager_tile_texture'] = self.manager_tile_texture
|
||||
data['manager_tiles'] = []
|
||||
for tile in self.manager_tiles:
|
||||
data['manager_tiles'].append(tile.save_json())
|
||||
data['manager_masks'] = []
|
||||
for mask in self.manager_masks:
|
||||
data['manager_masks'].append(mask.save_json())
|
||||
data['manager_patterns'] = []
|
||||
for pattern in self.manager_patterns:
|
||||
data['manager_patterns'].append(pattern.save_json())
|
||||
return data
|
||||
@@ -0,0 +1,396 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
#
|
||||
|
||||
|
||||
from base64 import b64decode, b64encode
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.util import ResStream
|
||||
|
||||
EFFETCT_TO_STRING = {
|
||||
0: 'PARTICLE',
|
||||
1: 'LIGHTNING',
|
||||
2: 'GEOMETRY',
|
||||
}
|
||||
|
||||
STRING_TO_EFFECT = {value: key for key, value in EFFETCT_TO_STRING.items()}
|
||||
|
||||
|
||||
class ArcParticle:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.particle_attached_bone = stream.read_dword()
|
||||
self.particle_count = stream.read_dword()
|
||||
self.particle_size = stream.read_float()
|
||||
self.particle_life = stream.read_float()
|
||||
self.particle_life_rand = stream.read_float()
|
||||
self.particle_shape_and_pos = stream.read_dword()
|
||||
self.particle_emitter_scale = stream.read_float()
|
||||
self.particle_pos_offset = stream.read_tuple()
|
||||
self.particle_ppos_reference = stream.read_tuple()
|
||||
self.particle_initial_velocities = stream.read_dword()
|
||||
self.particle_velocity_scale = stream.read_float()
|
||||
self.particle_vel_reference = stream.read_tuple()
|
||||
self.particle_dir_random = stream.read_float()
|
||||
self.particle_spd_random = stream.read_float()
|
||||
self.particle_initial_rot = stream.read_float()
|
||||
self.particle_initial_rot_random = stream.read_float()
|
||||
self.particle_incremental_rot = stream.read_float()
|
||||
self.particle_incremental_rot_random = stream.read_float()
|
||||
self.particle_color_keys = [
|
||||
[
|
||||
stream.read_float(),
|
||||
stream.read_float(),
|
||||
stream.read_float(),
|
||||
stream.read_float(),
|
||||
] for _ in range(5)
|
||||
]
|
||||
self.particle_color_keytimes = [stream.read_float() for _ in range(5)]
|
||||
self.particle_size_keys = [stream.read_float() for _ in range(5)]
|
||||
self.particle_targettype = stream.read_dword()
|
||||
self.particle_lifetime = stream.read_float()
|
||||
self.particle_texture = stream.read_dword()
|
||||
self.particle_blend_type = stream.read_dword()
|
||||
self.particle_attractor_bone = stream.read_dword()
|
||||
self.particle_directional_grav = stream.read_tuple()
|
||||
self.particle_field_function = stream.read_dword()
|
||||
self.particle_gravity_strength = stream.read_float()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.particle_attached_bone)
|
||||
stream.write_dword(self.particle_count)
|
||||
stream.write_float(self.particle_size)
|
||||
stream.write_float(self.particle_life)
|
||||
stream.write_float(self.particle_life_rand)
|
||||
stream.write_dword(self.particle_shape_and_pos)
|
||||
stream.write_float(self.particle_emitter_scale)
|
||||
stream.write_tuple(self.particle_pos_offset)
|
||||
stream.write_tuple(self.particle_ppos_reference)
|
||||
stream.write_dword(self.particle_initial_velocities)
|
||||
stream.write_float(self.particle_velocity_scale)
|
||||
stream.write_tuple(self.particle_vel_reference)
|
||||
stream.write_float(self.particle_dir_random)
|
||||
stream.write_float(self.particle_spd_random)
|
||||
stream.write_float(self.particle_initial_rot)
|
||||
stream.write_float(self.particle_initial_rot_random)
|
||||
stream.write_float(self.particle_incremental_rot)
|
||||
stream.write_float(self.particle_incremental_rot_random)
|
||||
for i in range(5):
|
||||
stream.write_float(self.particle_color_keys[i][0])
|
||||
stream.write_float(self.particle_color_keys[i][1])
|
||||
stream.write_float(self.particle_color_keys[i][2])
|
||||
stream.write_float(self.particle_color_keys[i][3])
|
||||
for i in range(5):
|
||||
stream.write_float(self.particle_color_keytimes[i])
|
||||
for i in range(5):
|
||||
stream.write_float(self.particle_size_keys[i])
|
||||
stream.write_dword(self.particle_targettype)
|
||||
stream.write_float(self.particle_lifetime)
|
||||
stream.write_dword(self.particle_texture)
|
||||
stream.write_dword(self.particle_blend_type)
|
||||
stream.write_dword(self.particle_attractor_bone)
|
||||
stream.write_tuple(self.particle_directional_grav)
|
||||
stream.write_dword(self.particle_field_function)
|
||||
stream.write_float(self.particle_gravity_strength)
|
||||
|
||||
def load_json(self, data):
|
||||
self.particle_attached_bone = data['particle_attached_bone']
|
||||
self.particle_count = data['particle_count']
|
||||
self.particle_size = data['particle_size']
|
||||
self.particle_life = data['particle_life']
|
||||
self.particle_life_rand = data['particle_life_rand']
|
||||
self.particle_shape_and_pos = data['particle_shape_and_pos']
|
||||
self.particle_emitter_scale = data['particle_emitter_scale']
|
||||
self.particle_pos_offset = data['particle_pos_offset']
|
||||
self.particle_ppos_reference = data['particle_ppos_reference']
|
||||
self.particle_initial_velocities = data['particle_initial_velocities']
|
||||
self.particle_velocity_scale = data['particle_velocity_scale']
|
||||
self.particle_vel_reference = data['particle_vel_reference']
|
||||
self.particle_dir_random = data['particle_dir_random']
|
||||
self.particle_spd_random = data['particle_spd_random']
|
||||
self.particle_initial_rot = data['particle_initial_rot']
|
||||
self.particle_initial_rot_random = data['particle_initial_rot_random']
|
||||
self.particle_incremental_rot = data['particle_incremental_rot']
|
||||
self.particle_incremental_rot_random = data['particle_incremental_rot_random']
|
||||
self.particle_color_keys = data['particle_color_keys']
|
||||
self.particle_color_keytimes = data['particle_color_keytimes']
|
||||
self.particle_size_keys = data['particle_size_keys']
|
||||
self.particle_targettype = data['particle_targettype']
|
||||
self.particle_lifetime = data['particle_lifetime']
|
||||
self.particle_texture = data['particle_texture']
|
||||
self.particle_blend_type = data['particle_blend_type']
|
||||
self.particle_attractor_bone = data['particle_attractor_bone']
|
||||
self.particle_directional_grav = data['particle_directional_grav']
|
||||
self.particle_field_function = data['particle_field_function']
|
||||
self.particle_gravity_strength = data['particle_gravity_strength']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['particle_attached_bone'] = self.particle_attached_bone
|
||||
data['particle_count'] = self.particle_count
|
||||
data['particle_size'] = self.particle_size
|
||||
data['particle_life'] = self.particle_life
|
||||
data['particle_life_rand'] = self.particle_life_rand
|
||||
data['particle_shape_and_pos'] = self.particle_shape_and_pos
|
||||
data['particle_emitter_scale'] = self.particle_emitter_scale
|
||||
data['particle_pos_offset'] = self.particle_pos_offset
|
||||
data['particle_ppos_reference'] = self.particle_ppos_reference
|
||||
data['particle_initial_velocities'] = self.particle_initial_velocities
|
||||
data['particle_velocity_scale'] = self.particle_velocity_scale
|
||||
data['particle_vel_reference'] = self.particle_vel_reference
|
||||
data['particle_dir_random'] = self.particle_dir_random
|
||||
data['particle_spd_random'] = self.particle_spd_random
|
||||
data['particle_initial_rot'] = self.particle_initial_rot
|
||||
data['particle_initial_rot_random'] = self.particle_initial_rot_random
|
||||
data['particle_incremental_rot'] = self.particle_incremental_rot
|
||||
data['particle_incremental_rot_random'] = self.particle_incremental_rot_random
|
||||
data['particle_color_keys'] = self.particle_color_keys
|
||||
data['particle_color_keytimes'] = self.particle_color_keytimes
|
||||
data['particle_size_keys'] = self.particle_size_keys
|
||||
data['particle_targettype'] = self.particle_targettype
|
||||
data['particle_lifetime'] = self.particle_lifetime
|
||||
data['particle_texture'] = self.particle_texture
|
||||
data['particle_blend_type'] = self.particle_blend_type
|
||||
data['particle_attractor_bone'] = self.particle_attractor_bone
|
||||
data['particle_directional_grav'] = self.particle_directional_grav
|
||||
data['particle_field_function'] = self.particle_field_function
|
||||
data['particle_gravity_strength'] = self.particle_gravity_strength
|
||||
return data
|
||||
|
||||
|
||||
class ArcLightning:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.lightning_texture = stream.read_dword()
|
||||
self.lightning_src_bone = stream.read_dword()
|
||||
self.lightning_dst_bone = stream.read_dword()
|
||||
self.lightning_width = stream.read_float()
|
||||
self.lightning_random_factor = stream.read_float()
|
||||
self.lightning_sine_factor = stream.read_float()
|
||||
self.lightning_sine_phase = stream.read_float()
|
||||
self.lightning_sine_phase_rep = stream.read_float()
|
||||
self.lightning_length = stream.read_float()
|
||||
self.lightning_random_move_speed = stream.read_float()
|
||||
self.lightning_color = stream.read_tuple()
|
||||
self.lightning_lifetime = stream.read_float()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.lightning_texture)
|
||||
stream.write_dword(self.lightning_src_bone)
|
||||
stream.write_dword(self.lightning_dst_bone)
|
||||
stream.write_float(self.lightning_width)
|
||||
stream.write_float(self.lightning_random_factor)
|
||||
stream.write_float(self.lightning_sine_factor)
|
||||
stream.write_float(self.lightning_sine_phase)
|
||||
stream.write_float(self.lightning_sine_phase_rep)
|
||||
stream.write_float(self.lightning_length)
|
||||
stream.write_float(self.lightning_random_move_speed)
|
||||
stream.write_tuple(self.lightning_color)
|
||||
stream.write_float(self.lightning_lifetime)
|
||||
|
||||
def load_json(self, data):
|
||||
self.lightning_texture = data['lightning_texture']
|
||||
self.lightning_src_bone = data['lightning_src_bone']
|
||||
self.lightning_dst_bone = data['lightning_dst_bone']
|
||||
self.lightning_width = data['lightning_width']
|
||||
self.lightning_random_factor = data['lightning_random_factor']
|
||||
self.lightning_sine_factor = data['lightning_sine_factor']
|
||||
self.lightning_sine_phase = data['lightning_sine_phase']
|
||||
self.lightning_sine_phase_rep = data['lightning_sine_phase_rep']
|
||||
self.lightning_length = data['lightning_length']
|
||||
self.lightning_random_move_speed = data['lightning_random_move_speed']
|
||||
self.lightning_color = data['lightning_color']
|
||||
self.lightning_lifetime = data['lightning_lifetime']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['lightning_texture'] = self.lightning_texture
|
||||
data['lightning_src_bone'] = self.lightning_src_bone
|
||||
data['lightning_dst_bone'] = self.lightning_dst_bone
|
||||
data['lightning_width'] = self.lightning_width
|
||||
data['lightning_random_factor'] = self.lightning_random_factor
|
||||
data['lightning_sine_factor'] = self.lightning_sine_factor
|
||||
data['lightning_sine_phase'] = self.lightning_sine_phase
|
||||
data['lightning_sine_phase_rep'] = self.lightning_sine_phase_rep
|
||||
data['lightning_length'] = self.lightning_length
|
||||
data['lightning_random_move_speed'] = self.lightning_random_move_speed
|
||||
data['lightning_color'] = self.lightning_color
|
||||
data['lightning_lifetime'] = self.lightning_lifetime
|
||||
return data
|
||||
|
||||
|
||||
class ArcGeometry:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.geometry_texture = stream.read_dword()
|
||||
self.geometry_src_bone = stream.read_dword()
|
||||
self.geometry_lifetime = stream.read_float()
|
||||
self.geometry_tex_trans_x = stream.read_float()
|
||||
self.geometry_tex_trans_y = stream.read_float()
|
||||
self.geometry_tex_rot = stream.read_float()
|
||||
self.geometry_grow = stream.read_tuple()
|
||||
self.geometry_tesselation = stream.read_float()
|
||||
self.geometry_size = stream.read_tuple()
|
||||
self.geometry_geo_rot_x = stream.read_float()
|
||||
self.geometry_fade_falloff = stream.read_float()
|
||||
self.geometry_fadein = stream.read_float()
|
||||
self.geometry_fadeout = stream.read_float()
|
||||
self.geometry_color = [stream.read_float() for _ in range(4)]
|
||||
self.geometry_type = stream.read_dword()
|
||||
self.geometry_texture_proj = stream.read_dword()
|
||||
self.geometry_fade_dir = stream.read_dword()
|
||||
self.geometry_offset = stream.read_tuple()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.geometry_texture)
|
||||
stream.write_dword(self.geometry_src_bone)
|
||||
stream.write_float(self.geometry_lifetime)
|
||||
stream.write_float(self.geometry_tex_trans_x)
|
||||
stream.write_float(self.geometry_tex_trans_y)
|
||||
stream.write_float(self.geometry_tex_rot)
|
||||
stream.write_tuple(self.geometry_grow)
|
||||
stream.write_float(self.geometry_tesselation)
|
||||
stream.write_tuple(self.geometry_size)
|
||||
stream.write_float(self.geometry_geo_rot_x)
|
||||
stream.write_float(self.geometry_fade_falloff)
|
||||
stream.write_float(self.geometry_fadein)
|
||||
stream.write_float(self.geometry_fadeout)
|
||||
for i in range(4):
|
||||
stream.write_float(self.geometry_color[i])
|
||||
stream.write_dword(self.geometry_type)
|
||||
stream.write_dword(self.geometry_texture_proj)
|
||||
stream.write_dword(self.geometry_fade_dir)
|
||||
stream.write_tuple(self.geometry_offset)
|
||||
|
||||
def load_json(self, data):
|
||||
self.geometry_texture = data['geometry_texture']
|
||||
self.geometry_src_bone = data['geometry_src_bone']
|
||||
self.geometry_lifetime = data['geometry_lifetime']
|
||||
self.geometry_tex_trans_x = data['geometry_tex_trans_x']
|
||||
self.geometry_tex_trans_y = data['geometry_tex_trans_y']
|
||||
self.geometry_tex_rot = data['geometry_tex_rot']
|
||||
self.geometry_grow = data['geometry_grow']
|
||||
self.geometry_tesselation = data['geometry_tesselation']
|
||||
self.geometry_size = data['geometry_size']
|
||||
self.geometry_geo_rot_x = data['geometry_geo_rot_x']
|
||||
self.geometry_fade_falloff = data['geometry_fade_falloff']
|
||||
self.geometry_fadein = data['geometry_fadein']
|
||||
self.geometry_fadeout = data['geometry_fadeout']
|
||||
self.geometry_color = data['geometry_color']
|
||||
self.geometry_type = data['geometry_type']
|
||||
self.geometry_texture_proj = data['geometry_texture_proj']
|
||||
self.geometry_fade_dir = data['geometry_fade_dir']
|
||||
self.geometry_offset = data['geometry_offset']
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['geometry_texture'] = self.geometry_texture
|
||||
data['geometry_src_bone'] = self.geometry_src_bone
|
||||
data['geometry_lifetime'] = self.geometry_lifetime
|
||||
data['geometry_tex_trans_x'] = self.geometry_tex_trans_x
|
||||
data['geometry_tex_trans_y'] = self.geometry_tex_trans_y
|
||||
data['geometry_tex_rot'] = self.geometry_tex_rot
|
||||
data['geometry_grow'] = self.geometry_grow
|
||||
data['geometry_tesselation'] = self.geometry_tesselation
|
||||
data['geometry_size'] = self.geometry_size
|
||||
data['geometry_geo_rot_x'] = self.geometry_geo_rot_x
|
||||
data['geometry_fade_falloff'] = self.geometry_fade_falloff
|
||||
data['geometry_fadein'] = self.geometry_fadein
|
||||
data['geometry_fadeout'] = self.geometry_fadeout
|
||||
data['geometry_color'] = self.geometry_color
|
||||
data['geometry_type'] = self.geometry_type
|
||||
data['geometry_texture_proj'] = self.geometry_texture_proj
|
||||
data['geometry_fade_dir'] = self.geometry_fade_dir
|
||||
data['geometry_offset'] = self.geometry_offset
|
||||
return data
|
||||
|
||||
|
||||
class ArcVisualEffect:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.effect_type = stream.read_dword()
|
||||
self.effect_time = stream.read_float()
|
||||
|
||||
if self.effect_type == 0:
|
||||
self.effect = ArcParticle()
|
||||
elif self.effect_type == 1:
|
||||
self.effect = ArcLightning()
|
||||
elif self.effect_type == 2:
|
||||
self.effect = ArcGeometry()
|
||||
self.effect.load_binary(stream)
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.effect_type)
|
||||
stream.write_float(self.effect_time)
|
||||
self.effect.save_binary(stream)
|
||||
|
||||
def load_json(self, data):
|
||||
self.effect_type = STRING_TO_EFFECT[data['effect_type']]
|
||||
self.effect_time = data['effect_time']
|
||||
if self.effect_type == 0:
|
||||
self.effect = ArcParticle()
|
||||
elif self.effect_type == 1:
|
||||
self.effect = ArcLightning()
|
||||
elif self.effect_type == 2:
|
||||
self.effect = ArcGeometry()
|
||||
self.effect.load_json(data['effect'])
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['effect_type'] = EFFETCT_TO_STRING[self.effect_type]
|
||||
data['effect_time'] = self.effect_time
|
||||
data['effect'] = self.effect.save_json()
|
||||
return data
|
||||
|
||||
|
||||
class ArcVisual:
|
||||
def load_binary(self, stream: ResStream):
|
||||
num_effects = stream.read_dword()
|
||||
|
||||
self.vfx_fail = None
|
||||
if num_effects == 1617156728:
|
||||
stream.buffer.seek(0, 0)
|
||||
self.vfx_fail = stream.buffer.read()
|
||||
return
|
||||
|
||||
self.vfx_duration = stream.read_float()
|
||||
self.vfx_effects = [ArcVisualEffect() for _ in range(num_effects)]
|
||||
for effect in self.vfx_effects:
|
||||
effect.load_binary(stream)
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
if self.vfx_fail:
|
||||
stream.buffer.write(self.vfx_fail)
|
||||
return
|
||||
|
||||
stream.write_dword(len(self.vfx_effects))
|
||||
stream.write_float(self.vfx_duration)
|
||||
for effect in self.vfx_effects:
|
||||
effect.save_binary(stream)
|
||||
|
||||
def load_json(self, data):
|
||||
self.vfx_fail = data.get('vfx_fail')
|
||||
if self.vfx_fail:
|
||||
self.vfx_fail = b64decode(self.vfx_fail)
|
||||
return
|
||||
|
||||
self.vfx_duration = data['vfx_duration']
|
||||
self.vfx_effects = []
|
||||
for effect_data in data['vfx_effects']:
|
||||
effect = ArcVisualEffect()
|
||||
effect.load_json(effect_data)
|
||||
self.vfx_effects.append(effect)
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
if self.vfx_fail:
|
||||
data['vfx_fail'] = b64encode(self.vfx_fail).decode()
|
||||
return data
|
||||
|
||||
data['vfx_duration'] = self.vfx_duration
|
||||
data['vfx_effects'] = []
|
||||
for effect in self.vfx_effects:
|
||||
data['vfx_effects'].append(effect.save_json())
|
||||
return data
|
||||
@@ -0,0 +1,7 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
@@ -0,0 +1,7 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
@@ -0,0 +1,62 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
ATTACK_RESIST_UNKNOWN = 0
|
||||
ATTACK_RESIST_SLASHING = 1
|
||||
ATTACK_RESIST_CRUSHING = 2
|
||||
ATTACK_RESIST_PIERCING = 3
|
||||
ATTACK_RESIST_POISON = 4
|
||||
ATTACK_RESIST_LIGHTNING = 5
|
||||
ATTACK_RESIST_MAGIC = 6
|
||||
ATTACK_RESIST_FIRE = 7
|
||||
ATTACK_RESIST_COLD = 8
|
||||
ATTACK_RESIST_MENTAL = 9
|
||||
ATTACK_RESIST_HOLY = 10
|
||||
ATTACK_RESIST_SIEGE = 11
|
||||
ATTACK_RESIST_HEALING = 12
|
||||
ATTACK_RESIST_BLEEDING = 13
|
||||
ATTACK_RESIST_UNHOLY = 14
|
||||
ATTACK_RESIST_ANTISIEGE = 15
|
||||
|
||||
ATTACK_RESIST_TO_STRING = {
|
||||
ATTACK_RESIST_UNKNOWN: 'UNKNOWN',
|
||||
ATTACK_RESIST_SLASHING: 'SLASHING',
|
||||
ATTACK_RESIST_CRUSHING: 'CRUSHING',
|
||||
ATTACK_RESIST_PIERCING: 'PIERCING',
|
||||
ATTACK_RESIST_POISON: 'POISON',
|
||||
ATTACK_RESIST_LIGHTNING: 'LIGHTNING',
|
||||
ATTACK_RESIST_MAGIC: 'MAGIC',
|
||||
ATTACK_RESIST_FIRE: 'FIRE',
|
||||
ATTACK_RESIST_COLD: 'COLD',
|
||||
ATTACK_RESIST_MENTAL: 'MENTAL',
|
||||
ATTACK_RESIST_HOLY: 'HOLY',
|
||||
ATTACK_RESIST_SIEGE: 'SIEGE',
|
||||
ATTACK_RESIST_HEALING: 'HEALING',
|
||||
ATTACK_RESIST_BLEEDING: 'BLEEDING',
|
||||
ATTACK_RESIST_UNHOLY: 'UNHOLY',
|
||||
ATTACK_RESIST_ANTISIEGE: 'ANTISIEGE',
|
||||
}
|
||||
|
||||
STRING_TO_ATTACK_RESIST = {
|
||||
'UNKNOWN': ATTACK_RESIST_UNKNOWN,
|
||||
'SLASHING': ATTACK_RESIST_SLASHING,
|
||||
'CRUSHING': ATTACK_RESIST_CRUSHING,
|
||||
'PIERCING': ATTACK_RESIST_PIERCING,
|
||||
'POISON': ATTACK_RESIST_POISON,
|
||||
'LIGHTNING': ATTACK_RESIST_LIGHTNING,
|
||||
'MAGIC': ATTACK_RESIST_MAGIC,
|
||||
'FIRE': ATTACK_RESIST_FIRE,
|
||||
'COLD': ATTACK_RESIST_COLD,
|
||||
'MENTAL': ATTACK_RESIST_MENTAL,
|
||||
'HOLY': ATTACK_RESIST_HOLY,
|
||||
'SIEGE': ATTACK_RESIST_SIEGE,
|
||||
'HEALING': ATTACK_RESIST_HEALING,
|
||||
'BLEEDING': ATTACK_RESIST_BLEEDING,
|
||||
'UNHOLY': ATTACK_RESIST_UNHOLY,
|
||||
'ANTISIEGE': ATTACK_RESIST_ANTISIEGE,
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
DOOR_TYPE_ROTATE = 0
|
||||
DOOR_TYPE_SLIDE = 1
|
||||
|
||||
DOOR_TYPE_TO_STRING = {
|
||||
DOOR_TYPE_ROTATE: 'ROTATE',
|
||||
DOOR_TYPE_SLIDE: 'SLIDE',
|
||||
}
|
||||
|
||||
STRING_TO_DOOR_TYPE = {
|
||||
'ROTATE': DOOR_TYPE_ROTATE,
|
||||
'SLIDE': DOOR_TYPE_SLIDE,
|
||||
}
|
||||
|
||||
DOOR_MOVEMENT_AXIS_XAXIS = 0
|
||||
DOOR_MOVEMENT_AXIS_YAXIS = 1
|
||||
DOOR_MOVEMENT_AXIS_ZAXIS = 2
|
||||
|
||||
DOOR_MOVEMENT_AXIS_TO_STRING = {
|
||||
DOOR_MOVEMENT_AXIS_XAXIS: 'XAXIS',
|
||||
DOOR_MOVEMENT_AXIS_YAXIS: 'YAXIS',
|
||||
DOOR_MOVEMENT_AXIS_ZAXIS: 'ZAXIS',
|
||||
}
|
||||
|
||||
STRING_TO_DOOR_MOVEMENT_AXIS = {
|
||||
'XAXIS': DOOR_MOVEMENT_AXIS_XAXIS,
|
||||
'YAXIS': DOOR_MOVEMENT_AXIS_YAXIS,
|
||||
'ZAXIS': DOOR_MOVEMENT_AXIS_ZAXIS,
|
||||
}
|
||||
|
||||
DOOR_SWING_DIRECTION_CLOCKWISE = 0
|
||||
DOOR_SWING_DIRECTION_COUNTERCLOCKWISE = 1
|
||||
|
||||
DOOR_SWING_DIRECTION_TO_STRING = {
|
||||
DOOR_SWING_DIRECTION_CLOCKWISE: 'CLOCKWISE',
|
||||
DOOR_SWING_DIRECTION_COUNTERCLOCKWISE: 'COUNTERCLOCKWISE',
|
||||
}
|
||||
|
||||
STRING_TO_DOOR_SWING_DIRECTION = {
|
||||
'CLOCKWISE': DOOR_SWING_DIRECTION_CLOCKWISE,
|
||||
'COUNTERCLOCKWISE': DOOR_SWING_DIRECTION_COUNTERCLOCKWISE,
|
||||
}
|
||||
@@ -0,0 +1,332 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
ITEM_FLAG_NONE = 1 << 0
|
||||
ITEM_FLAG_INDESTRUCTIBLE = 1 << 1
|
||||
ITEM_FLAG_IDENTIFIED = 1 << 2
|
||||
ITEM_FLAG_NOBOND = 1 << 3
|
||||
ITEM_FLAG_NOQUIT = 1 << 4
|
||||
ITEM_FLAG_MAGIC = 1 << 5
|
||||
ITEM_FLAG_NODROP = 1 << 6
|
||||
ITEM_FLAG_RARE = 1 << 7
|
||||
ITEM_FLAG_NUM = 7
|
||||
|
||||
ITEM_FLAG_TO_STRING = {
|
||||
ITEM_FLAG_NONE: 'None',
|
||||
ITEM_FLAG_INDESTRUCTIBLE: 'Indestructible',
|
||||
ITEM_FLAG_IDENTIFIED: 'Identified',
|
||||
ITEM_FLAG_NOBOND: 'NoBond',
|
||||
ITEM_FLAG_NOQUIT: 'NoQuit',
|
||||
ITEM_FLAG_MAGIC: 'Magic',
|
||||
ITEM_FLAG_NODROP: 'NoDrop',
|
||||
ITEM_FLAG_RARE: 'Rare',
|
||||
}
|
||||
|
||||
STRING_TO_ITEM_FLAG = {
|
||||
'None': ITEM_FLAG_NONE,
|
||||
'Indestructible': ITEM_FLAG_INDESTRUCTIBLE,
|
||||
'Identified': ITEM_FLAG_IDENTIFIED,
|
||||
'NoBond': ITEM_FLAG_NOBOND,
|
||||
'NoQuit': ITEM_FLAG_NOQUIT,
|
||||
'Magic': ITEM_FLAG_MAGIC,
|
||||
'NoDrop': ITEM_FLAG_NODROP,
|
||||
'Rare': ITEM_FLAG_RARE,
|
||||
}
|
||||
|
||||
ITEM_EQUIP_SLOT_NONE = 0
|
||||
ITEM_EQUIP_SLOT_RHELD = 1 << 0
|
||||
ITEM_EQUIP_SLOT_LHELD = 1 << 1
|
||||
ITEM_EQUIP_SLOT_HELM = 1 << 2
|
||||
ITEM_EQUIP_SLOT_CHEST = 1 << 3
|
||||
ITEM_EQUIP_SLOT_SLEEVES = 1 << 4
|
||||
ITEM_EQUIP_SLOT_HANDS = 1 << 5
|
||||
ITEM_EQUIP_SLOT_RRING = 1 << 6
|
||||
ITEM_EQUIP_SLOT_LRING = 1 << 7
|
||||
ITEM_EQUIP_SLOT_AMULET = 1 << 8
|
||||
ITEM_EQUIP_SLOT_LEGS = 1 << 9
|
||||
ITEM_EQUIP_SLOT_FEET = 1 << 10
|
||||
ITEM_EQUIP_SLOT_CLOAK = 1 << 11
|
||||
ITEM_EQUIP_SLOT_SHIN = 1 << 12
|
||||
ITEM_EQUIP_SLOT_UPLEGS = 1 << 13
|
||||
ITEM_EQUIP_SLOT_UPARM = 1 << 14
|
||||
ITEM_EQUIP_SLOT_WINGS = 1 << 15
|
||||
ITEM_EQUIP_SLOT_BEARD = 1 << 16
|
||||
ITEM_EQUIP_SLOT_HAIR = 1 << 17
|
||||
ITEM_EQUIP_SLOT_NUM = 18
|
||||
|
||||
ITEM_EQIP_SLOT_TO_STRING = {
|
||||
ITEM_EQUIP_SLOT_NONE: 'NONE',
|
||||
ITEM_EQUIP_SLOT_RHELD: 'RHELD',
|
||||
ITEM_EQUIP_SLOT_LHELD: 'LHELD',
|
||||
ITEM_EQUIP_SLOT_HELM: 'HELM',
|
||||
ITEM_EQUIP_SLOT_CHEST: 'CHEST',
|
||||
ITEM_EQUIP_SLOT_SLEEVES: 'SLEEVES',
|
||||
ITEM_EQUIP_SLOT_HANDS: 'HANDS',
|
||||
ITEM_EQUIP_SLOT_RRING: 'RRING',
|
||||
ITEM_EQUIP_SLOT_LRING: 'LRING',
|
||||
ITEM_EQUIP_SLOT_AMULET: 'AMULET',
|
||||
ITEM_EQUIP_SLOT_LEGS: 'LEGS',
|
||||
ITEM_EQUIP_SLOT_FEET: 'FEET',
|
||||
ITEM_EQUIP_SLOT_CLOAK: 'CLOAK',
|
||||
ITEM_EQUIP_SLOT_SHIN: 'SHIN',
|
||||
ITEM_EQUIP_SLOT_UPLEGS: 'UPLEGS',
|
||||
ITEM_EQUIP_SLOT_UPARM: 'UPARM',
|
||||
ITEM_EQUIP_SLOT_WINGS: 'WINGS',
|
||||
ITEM_EQUIP_SLOT_BEARD: 'BEARD',
|
||||
ITEM_EQUIP_SLOT_HAIR: 'HAIR',
|
||||
}
|
||||
|
||||
STRING_TO_ITEM_EQIP_SLOT = {
|
||||
'NONE': ITEM_EQUIP_SLOT_NONE,
|
||||
'RHELD': ITEM_EQUIP_SLOT_RHELD,
|
||||
'LHELD': ITEM_EQUIP_SLOT_LHELD,
|
||||
'HELM': ITEM_EQUIP_SLOT_HELM,
|
||||
'CHEST': ITEM_EQUIP_SLOT_CHEST,
|
||||
'SLEEVES': ITEM_EQUIP_SLOT_SLEEVES,
|
||||
'HANDS': ITEM_EQUIP_SLOT_HANDS,
|
||||
'RRING': ITEM_EQUIP_SLOT_RRING,
|
||||
'LRING': ITEM_EQUIP_SLOT_LRING,
|
||||
'AMULET': ITEM_EQUIP_SLOT_AMULET,
|
||||
'LEGS': ITEM_EQUIP_SLOT_LEGS,
|
||||
'FEET': ITEM_EQUIP_SLOT_FEET,
|
||||
'CLOAK': ITEM_EQUIP_SLOT_CLOAK,
|
||||
'SHIN': ITEM_EQUIP_SLOT_SHIN,
|
||||
'UPLEGS': ITEM_EQUIP_SLOT_UPLEGS,
|
||||
'UPARM': ITEM_EQUIP_SLOT_UPARM,
|
||||
'WINGS': ITEM_EQUIP_SLOT_WINGS,
|
||||
'BEARD': ITEM_EQUIP_SLOT_BEARD,
|
||||
'HAIR': ITEM_EQUIP_SLOT_HAIR,
|
||||
}
|
||||
|
||||
ITEM_TYPE_UNKNOWN = 0
|
||||
ITEM_TYPE_WEAPON = 1
|
||||
ITEM_TYPE_ARMOR = 2
|
||||
ITEM_TYPE_BASE = 3
|
||||
ITEM_TYPE_GOLD = 4
|
||||
ITEM_TYPE_SCROLL = 5
|
||||
ITEM_TYPE_BOOK = 6
|
||||
ITEM_TYPE_WAND = 7
|
||||
ITEM_TYPE_POTION = 8
|
||||
ITEM_TYPE_KEY = 9
|
||||
ITEM_TYPE_CHARTER = 10
|
||||
ITEM_TYPE_GUILDTREE = 11
|
||||
ITEM_TYPE_SOUNDSOURCE = 12
|
||||
ITEM_TYPE_JEWELRY = 13
|
||||
ITEM_TYPE_CONTAINER = 14
|
||||
ITEM_TYPE_FOUNTAIN = 15
|
||||
ITEM_TYPE_FOOD = 16
|
||||
ITEM_TYPE_DRINKCONTAINER = 17
|
||||
ITEM_TYPE_MAPMARKER = 18
|
||||
ITEM_TYPE_DEED = 19
|
||||
ITEM_TYPE_EMPLOYMENTCONTRACT = 20
|
||||
ITEM_TYPE_PETTOTEM = 21
|
||||
ITEM_TYPE_SLAVECOLLAR = 22
|
||||
ITEM_TYPE_BLANKKEY = 23
|
||||
ITEM_TYPE_WARRANT = 24
|
||||
ITEM_TYPE_FURNITUREDEED = 25
|
||||
ITEM_TYPE_TENT = 26
|
||||
ITEM_TYPE_REAGENT = 27
|
||||
ITEM_TYPE_DEVICE = 28
|
||||
ITEM_TYPE_FORMULA = 29
|
||||
ITEM_TYPE_BUCKET = 30
|
||||
ITEM_TYPE_TREASURE = 31
|
||||
ITEM_TYPE_RUNE = 32
|
||||
ITEM_TYPE_OFFERING = 33
|
||||
ITEM_TYPE_RESOURCE = 34
|
||||
ITEM_TYPE_REALMCHARTER = 35
|
||||
|
||||
ITEM_TYPE_TO_STRING = {
|
||||
ITEM_TYPE_UNKNOWN: 'UNKNOWN',
|
||||
ITEM_TYPE_WEAPON: 'WEAPON',
|
||||
ITEM_TYPE_ARMOR: 'ARMOR',
|
||||
ITEM_TYPE_BASE: 'BASE',
|
||||
ITEM_TYPE_GOLD: 'GOLD',
|
||||
ITEM_TYPE_SCROLL: 'SCROLL',
|
||||
ITEM_TYPE_BOOK: 'BOOK',
|
||||
ITEM_TYPE_WAND: 'WAND',
|
||||
ITEM_TYPE_POTION: 'POTION',
|
||||
ITEM_TYPE_KEY: 'KEY',
|
||||
ITEM_TYPE_CHARTER: 'CHARTER',
|
||||
ITEM_TYPE_GUILDTREE: 'GUILDTREE',
|
||||
ITEM_TYPE_SOUNDSOURCE: 'SOUNDSOURCE',
|
||||
ITEM_TYPE_JEWELRY: 'JEWELRY',
|
||||
ITEM_TYPE_CONTAINER: 'CONTAINER',
|
||||
ITEM_TYPE_FOUNTAIN: 'FOUNTAIN',
|
||||
ITEM_TYPE_FOOD: 'FOOD',
|
||||
ITEM_TYPE_DRINKCONTAINER: 'DRINKCONTAINER',
|
||||
ITEM_TYPE_MAPMARKER: 'MAPMARKER',
|
||||
ITEM_TYPE_DEED: 'DEED',
|
||||
ITEM_TYPE_EMPLOYMENTCONTRACT: 'EMPLOYMENTCONTRACT',
|
||||
ITEM_TYPE_PETTOTEM: 'PETTOTEM',
|
||||
ITEM_TYPE_SLAVECOLLAR: 'SLAVECOLLAR',
|
||||
ITEM_TYPE_BLANKKEY: 'BLANKKEY',
|
||||
ITEM_TYPE_WARRANT: 'WARRANT',
|
||||
ITEM_TYPE_FURNITUREDEED: 'FURNITUREDEED',
|
||||
ITEM_TYPE_TENT: 'TENT',
|
||||
ITEM_TYPE_REAGENT: 'REAGENT',
|
||||
ITEM_TYPE_DEVICE: 'DEVICE',
|
||||
ITEM_TYPE_FORMULA: 'FORMULA',
|
||||
ITEM_TYPE_BUCKET: 'BUCKET',
|
||||
ITEM_TYPE_TREASURE: 'TREASURE',
|
||||
ITEM_TYPE_RUNE: 'RUNE',
|
||||
ITEM_TYPE_OFFERING: 'OFFERING',
|
||||
ITEM_TYPE_RESOURCE: 'RESOURCE',
|
||||
ITEM_TYPE_REALMCHARTER: 'REALMCHARTER',
|
||||
}
|
||||
|
||||
STRING_TO_ITEM_TYPE = {
|
||||
'UNKNOWN': ITEM_TYPE_UNKNOWN,
|
||||
'WEAPON': ITEM_TYPE_WEAPON,
|
||||
'ARMOR': ITEM_TYPE_ARMOR,
|
||||
'BASE': ITEM_TYPE_BASE,
|
||||
'GOLD': ITEM_TYPE_GOLD,
|
||||
'SCROLL': ITEM_TYPE_SCROLL,
|
||||
'BOOK': ITEM_TYPE_BOOK,
|
||||
'WAND': ITEM_TYPE_WAND,
|
||||
'POTION': ITEM_TYPE_POTION,
|
||||
'KEY': ITEM_TYPE_KEY,
|
||||
'CHARTER': ITEM_TYPE_CHARTER,
|
||||
'GUILDTREE': ITEM_TYPE_GUILDTREE,
|
||||
'SOUNDSOURCE': ITEM_TYPE_SOUNDSOURCE,
|
||||
'JEWELRY': ITEM_TYPE_JEWELRY,
|
||||
'CONTAINER': ITEM_TYPE_CONTAINER,
|
||||
'FOUNTAIN': ITEM_TYPE_FOUNTAIN,
|
||||
'FOOD': ITEM_TYPE_FOOD,
|
||||
'DRINKCONTAINER': ITEM_TYPE_DRINKCONTAINER,
|
||||
'MAPMARKER': ITEM_TYPE_MAPMARKER,
|
||||
'DEED': ITEM_TYPE_DEED,
|
||||
'EMPLOYMENTCONTRACT': ITEM_TYPE_EMPLOYMENTCONTRACT,
|
||||
'PETTOTEM': ITEM_TYPE_PETTOTEM,
|
||||
'SLAVECOLLAR': ITEM_TYPE_SLAVECOLLAR,
|
||||
'BLANKKEY': ITEM_TYPE_BLANKKEY,
|
||||
'WARRANT': ITEM_TYPE_WARRANT,
|
||||
'FURNITUREDEED': ITEM_TYPE_FURNITUREDEED,
|
||||
'TENT': ITEM_TYPE_TENT,
|
||||
'REAGENT': ITEM_TYPE_REAGENT,
|
||||
'DEVICE': ITEM_TYPE_DEVICE,
|
||||
'FORMULA': ITEM_TYPE_FORMULA,
|
||||
'BUCKET': ITEM_TYPE_BUCKET,
|
||||
'TREASURE': ITEM_TYPE_TREASURE,
|
||||
'RUNE': ITEM_TYPE_RUNE,
|
||||
'OFFERING': ITEM_TYPE_OFFERING,
|
||||
'RESOURCE': ITEM_TYPE_RESOURCE,
|
||||
'REALMCHARTER': ITEM_TYPE_REALMCHARTER,
|
||||
}
|
||||
|
||||
ITEM_USE_FLAGS_NONE = 0
|
||||
ITEM_USE_FLAGS_USE_SELF = 1 << 0
|
||||
ITEM_USE_FLAGS_USE_TARGET = 1 << 1
|
||||
ITEM_USE_FLAGS_EMPTY_DESTROY = 1 << 2
|
||||
ITEM_USE_FLAGS_EMPTY_NEWITEM = 1 << 3
|
||||
ITEM_USE_FLAGS_NUM = 4
|
||||
|
||||
ITEM_USE_FLAGS_TO_STRING = {
|
||||
ITEM_USE_FLAGS_NONE: 'NONE',
|
||||
ITEM_USE_FLAGS_USE_SELF: 'USE_SELF',
|
||||
ITEM_USE_FLAGS_USE_TARGET: 'USE_TARGET',
|
||||
ITEM_USE_FLAGS_EMPTY_DESTROY: 'EMPTY_DESTROY',
|
||||
ITEM_USE_FLAGS_EMPTY_NEWITEM: 'EMPTY_NEWITEM',
|
||||
}
|
||||
|
||||
STRING_TO_ITEM_USE_FLAGS = {
|
||||
'NONE': ITEM_USE_FLAGS_NONE,
|
||||
'USE_SELF': ITEM_USE_FLAGS_USE_SELF,
|
||||
'USE_TARGET': ITEM_USE_FLAGS_USE_TARGET,
|
||||
'EMPTY_DESTROY': ITEM_USE_FLAGS_EMPTY_DESTROY,
|
||||
'EMPTY_NEWITEM': ITEM_USE_FLAGS_EMPTY_NEWITEM,
|
||||
}
|
||||
|
||||
ITEM_SHEATHSLOT_UNKNOWN = 0
|
||||
ITEM_SHEATHSLOT_BACK = 1
|
||||
ITEM_SHEATHSLOT_WAIST = 2
|
||||
ITEM_SHEATHSLOT_NONE = 4
|
||||
|
||||
ITEM_SHEATHSLOT_TO_STRING = {
|
||||
ITEM_SHEATHSLOT_NONE: 'NONE',
|
||||
ITEM_SHEATHSLOT_UNKNOWN: 'UNKNOWN',
|
||||
ITEM_SHEATHSLOT_BACK: 'BACK',
|
||||
ITEM_SHEATHSLOT_WAIST: 'WAIST',
|
||||
}
|
||||
|
||||
STRING_TO_ITEM_SHEATHSLOT = {
|
||||
'NONE': ITEM_SHEATHSLOT_NONE,
|
||||
'UNKNOWN': ITEM_SHEATHSLOT_UNKNOWN,
|
||||
'BACK': ITEM_SHEATHSLOT_BACK,
|
||||
'WAIST': ITEM_SHEATHSLOT_WAIST,
|
||||
}
|
||||
|
||||
DAMAGE_UNKNOWN = 0
|
||||
DAMAGE_SLASHING = 1
|
||||
DAMAGE_CRUSHING = 2
|
||||
DAMAGE_PIERCING = 3
|
||||
DAMAGE_POISON = 4
|
||||
DAMAGE_LIGHTNING = 5
|
||||
DAMAGE_MAGIC = 6
|
||||
DAMAGE_FIRE = 7
|
||||
DAMAGE_COLD = 8
|
||||
DAMAGE_MENTAL = 9
|
||||
DAMAGE_HOLY = 10
|
||||
DAMAGE_SIEGE = 11
|
||||
DAMAGE_HEALING = 12
|
||||
DAMAGE_BLEEDING = 13
|
||||
DAMAGE_UNHOLY = 14
|
||||
DAMAGE_ANTISIEGE = 15
|
||||
|
||||
DAMAGE_TO_STRING = {
|
||||
DAMAGE_UNKNOWN: 'UNKNOWN',
|
||||
DAMAGE_SLASHING: 'SLASHING',
|
||||
DAMAGE_CRUSHING: 'CRUSHING',
|
||||
DAMAGE_PIERCING: 'PIERCING',
|
||||
DAMAGE_POISON: 'POISON',
|
||||
DAMAGE_LIGHTNING: 'LIGHTNING',
|
||||
DAMAGE_MAGIC: 'MAGIC',
|
||||
DAMAGE_FIRE: 'FIRE',
|
||||
DAMAGE_COLD: 'COLD',
|
||||
DAMAGE_MENTAL: 'MENTAL',
|
||||
DAMAGE_HOLY: 'HOLY',
|
||||
DAMAGE_SIEGE: 'SIEGE',
|
||||
DAMAGE_HEALING: 'HEALING',
|
||||
DAMAGE_BLEEDING: 'BLEEDING',
|
||||
DAMAGE_UNHOLY: 'UNHOLY',
|
||||
DAMAGE_ANTISIEGE: 'ANTISIEGE',
|
||||
}
|
||||
|
||||
STRING_TO_DAMAGE = {
|
||||
'UNKNOWN': DAMAGE_UNKNOWN,
|
||||
'SLASHING': DAMAGE_SLASHING,
|
||||
'CRUSHING': DAMAGE_CRUSHING,
|
||||
'PIERCING': DAMAGE_PIERCING,
|
||||
'POISON': DAMAGE_POISON,
|
||||
'LIGHTNING': DAMAGE_LIGHTNING,
|
||||
'MAGIC': DAMAGE_MAGIC,
|
||||
'FIRE': DAMAGE_FIRE,
|
||||
'COLD': DAMAGE_COLD,
|
||||
'MENTAL': DAMAGE_MENTAL,
|
||||
'HOLY': DAMAGE_HOLY,
|
||||
'SIEGE': DAMAGE_SIEGE,
|
||||
'HEALING': DAMAGE_HEALING,
|
||||
'BLEEDING': DAMAGE_BLEEDING,
|
||||
'UNHOLY': DAMAGE_UNHOLY,
|
||||
'ANTISIEGE': DAMAGE_ANTISIEGE,
|
||||
}
|
||||
|
||||
ITEM_SEX_REQ_NONE = 0
|
||||
ITEM_SEX_REQ_MALE = 1
|
||||
ITEM_SEX_REQ_FEMALE = 2
|
||||
|
||||
ITEM_SEX_REQ_TO_STRING = {
|
||||
ITEM_SEX_REQ_NONE: 'NONE',
|
||||
ITEM_SEX_REQ_MALE: 'MALE',
|
||||
ITEM_SEX_REQ_FEMALE: 'FEMALE',
|
||||
}
|
||||
|
||||
STRING_TO_ITEM_SEX_REQ = {
|
||||
'NONE': ITEM_SEX_REQ_NONE,
|
||||
'MALE': ITEM_SEX_REQ_MALE,
|
||||
'FEMALE': ITEM_SEX_REQ_FEMALE,
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
OBJECT_TYPE_LIGHT = 1
|
||||
OBJECT_TYPE_DOOR = 2
|
||||
OBJECT_TYPE_STATIC = 3
|
||||
OBJECT_TYPE_STRUCTURE = 4
|
||||
OBJECT_TYPE_ASSETSTRUCTURE = 5
|
||||
OBJECT_TYPE_DUNGEONUNIT = 6
|
||||
OBJECT_TYPE_DUNGEONEXIT = 7
|
||||
OBJECT_TYPE_DUNGEONSTAIR = 8
|
||||
OBJECT_TYPE_ITEM = 9
|
||||
OBJECT_TYPE_TERRAIN = 10
|
||||
OBJECT_TYPE_PLAYER = 11
|
||||
OBJECT_TYPE_MOBILE = 12
|
||||
OBJECT_TYPE_RUNE = 13
|
||||
OBJECT_TYPE_CONTAINER = 14
|
||||
OBJECT_TYPE_DEED = 15
|
||||
OBJECT_TYPE_KEY = 16
|
||||
OBJECT_TYPE_ASSET = 17
|
||||
OBJECT_TYPE_NUM = 18
|
||||
OBJECT_TYPE_OBJECT = 19
|
||||
|
||||
OBJECT_TYPE_TO_STRING = {
|
||||
OBJECT_TYPE_LIGHT: 'LIGHT',
|
||||
OBJECT_TYPE_DOOR: 'DOOR',
|
||||
OBJECT_TYPE_STATIC: 'STATIC',
|
||||
OBJECT_TYPE_STRUCTURE: 'STRUCTURE',
|
||||
OBJECT_TYPE_ASSETSTRUCTURE: 'ASSETSTRUCTURE',
|
||||
OBJECT_TYPE_DUNGEONUNIT: 'DUNGEONUNIT',
|
||||
OBJECT_TYPE_DUNGEONEXIT: 'DUNGEONEXIT',
|
||||
OBJECT_TYPE_DUNGEONSTAIR: 'DUNGEONSTAIR',
|
||||
OBJECT_TYPE_ITEM: 'ITEM',
|
||||
OBJECT_TYPE_TERRAIN: 'TERRAIN',
|
||||
OBJECT_TYPE_PLAYER: 'PLAYER',
|
||||
OBJECT_TYPE_MOBILE: 'MOBILE',
|
||||
OBJECT_TYPE_RUNE: 'RUNE',
|
||||
OBJECT_TYPE_CONTAINER: 'CONTAINER',
|
||||
OBJECT_TYPE_DEED: 'DEED',
|
||||
OBJECT_TYPE_KEY: 'KEY',
|
||||
OBJECT_TYPE_ASSET: 'ASSET',
|
||||
OBJECT_TYPE_NUM: 'NUM',
|
||||
OBJECT_TYPE_OBJECT: 'OBJECT',
|
||||
}
|
||||
|
||||
STRING_TO_OBJECT_TYPE = {
|
||||
'LIGHT': OBJECT_TYPE_LIGHT,
|
||||
'DOOR': OBJECT_TYPE_DOOR,
|
||||
'STATIC': OBJECT_TYPE_STATIC,
|
||||
'STRUCTURE': OBJECT_TYPE_STRUCTURE,
|
||||
'ASSETSTRUCTURE': OBJECT_TYPE_ASSETSTRUCTURE,
|
||||
'DUNGEONUNIT': OBJECT_TYPE_DUNGEONUNIT,
|
||||
'DUNGEONEXIT': OBJECT_TYPE_DUNGEONEXIT,
|
||||
'DUNGEONSTAIR': OBJECT_TYPE_DUNGEONSTAIR,
|
||||
'ITEM': OBJECT_TYPE_ITEM,
|
||||
'TERRAIN': OBJECT_TYPE_TERRAIN,
|
||||
'PLAYER': OBJECT_TYPE_PLAYER,
|
||||
'MOBILE': OBJECT_TYPE_MOBILE,
|
||||
'RUNE': OBJECT_TYPE_RUNE,
|
||||
'CONTAINER': OBJECT_TYPE_CONTAINER,
|
||||
'DEED': OBJECT_TYPE_DEED,
|
||||
'KEY': OBJECT_TYPE_KEY,
|
||||
'ASSET': OBJECT_TYPE_ASSET,
|
||||
'NUM': OBJECT_TYPE_NUM,
|
||||
'OBJECT': OBJECT_TYPE_OBJECT,
|
||||
}
|
||||
|
||||
SOUND_TYPE_WALK = 1
|
||||
SOUND_TYPE_RUN = 2
|
||||
SOUND_TYPE_ATTACK = 3
|
||||
SOUND_TYPE_HIT = 4
|
||||
SOUND_TYPE_MISS = 5
|
||||
SOUND_TYPE_BLOCK = 6
|
||||
SOUND_TYPE_GETHIT = 7
|
||||
SOUND_TYPE_CANTCARRY = 8
|
||||
SOUND_TYPE_CANTDO = 9
|
||||
SOUND_TYPE_CANTUSE = 10
|
||||
SOUND_TYPE_LOCKED = 11
|
||||
SOUND_TYPE_NEEDMANA = 12
|
||||
SOUND_TYPE_NEEDSTAMINA = 13
|
||||
SOUND_TYPE_JUNKITEM = 14
|
||||
SOUND_TYPE_LEVELGAIN = 15
|
||||
SOUND_TYPE_PICKUPITEM = 16
|
||||
SOUND_TYPE_DROPITEM = 17
|
||||
SOUND_TYPE_USEITEM = 18
|
||||
SOUND_TYPE_FLEE = 19
|
||||
SOUND_TYPE_DEATH = 20
|
||||
SOUND_TYPE_INVALIDTARGET = 21
|
||||
SOUND_TYPE_OPEN = 22
|
||||
SOUND_TYPE_CLOSE = 23
|
||||
SOUND_TYPE_DESTROY = 24
|
||||
SOUND_TYPE_POWERCAST = 25
|
||||
SOUND_TYPE_POWEREFFECT = 26
|
||||
SOUND_TYPE_POWERFAIL = 27
|
||||
SOUND_TYPE_HUDOPEN = 28
|
||||
SOUND_TYPE_HUDCLOSE = 29
|
||||
SOUND_TYPE_SHEATH = 30
|
||||
SOUND_TYPE_UNSHEATH = 31
|
||||
SOUND_TYPE_BUILDINGDESTROYED = 32
|
||||
SOUND_TYPE_BURN = 33
|
||||
SOUND_TYPE_IDLE = 34
|
||||
|
||||
SOUND_TYPE_TO_STRING = {
|
||||
SOUND_TYPE_WALK: 'WALK',
|
||||
SOUND_TYPE_RUN: 'RUN',
|
||||
SOUND_TYPE_ATTACK: 'ATTACK',
|
||||
SOUND_TYPE_HIT: 'HIT',
|
||||
SOUND_TYPE_MISS: 'MISS',
|
||||
SOUND_TYPE_BLOCK: 'BLOCK',
|
||||
SOUND_TYPE_GETHIT: 'GETHIT',
|
||||
SOUND_TYPE_CANTCARRY: 'CANTCARRY',
|
||||
SOUND_TYPE_CANTDO: 'CANTDO',
|
||||
SOUND_TYPE_CANTUSE: 'CANTUSE',
|
||||
SOUND_TYPE_LOCKED: 'LOCKED',
|
||||
SOUND_TYPE_NEEDMANA: 'NEEDMANA',
|
||||
SOUND_TYPE_NEEDSTAMINA: 'NEEDSTAMINA',
|
||||
SOUND_TYPE_JUNKITEM: 'JUNKITEM',
|
||||
SOUND_TYPE_LEVELGAIN: 'LEVELGAIN',
|
||||
SOUND_TYPE_PICKUPITEM: 'PICKUPITEM',
|
||||
SOUND_TYPE_DROPITEM: 'DROPITEM',
|
||||
SOUND_TYPE_USEITEM: 'USEITEM',
|
||||
SOUND_TYPE_FLEE: 'FLEE',
|
||||
SOUND_TYPE_DEATH: 'DEATH',
|
||||
SOUND_TYPE_INVALIDTARGET: 'INVALIDTARGET',
|
||||
SOUND_TYPE_OPEN: 'OPEN',
|
||||
SOUND_TYPE_CLOSE: 'CLOSE',
|
||||
SOUND_TYPE_DESTROY: 'DESTROY',
|
||||
SOUND_TYPE_POWERCAST: 'POWERCAST',
|
||||
SOUND_TYPE_POWEREFFECT: 'POWEREFFECT',
|
||||
SOUND_TYPE_POWERFAIL: 'POWERFAIL',
|
||||
SOUND_TYPE_HUDOPEN: 'HUDOPEN',
|
||||
SOUND_TYPE_HUDCLOSE: 'HUDCLOSE',
|
||||
SOUND_TYPE_SHEATH: 'SHEATH',
|
||||
SOUND_TYPE_UNSHEATH: 'UNSHEATH',
|
||||
SOUND_TYPE_BUILDINGDESTROYED: 'BUILDINGDESTROYED',
|
||||
SOUND_TYPE_BURN: 'BURN',
|
||||
SOUND_TYPE_IDLE: 'IDLE',
|
||||
}
|
||||
|
||||
STRING_TO_SOUND_TYPE = {
|
||||
'WALK': SOUND_TYPE_WALK,
|
||||
'RUN': SOUND_TYPE_RUN,
|
||||
'ATTACK': SOUND_TYPE_ATTACK,
|
||||
'HIT': SOUND_TYPE_HIT,
|
||||
'MISS': SOUND_TYPE_MISS,
|
||||
'BLOCK': SOUND_TYPE_BLOCK,
|
||||
'GETHIT': SOUND_TYPE_GETHIT,
|
||||
'CANTCARRY': SOUND_TYPE_CANTCARRY,
|
||||
'CANTDO': SOUND_TYPE_CANTDO,
|
||||
'CANTUSE': SOUND_TYPE_CANTUSE,
|
||||
'LOCKED': SOUND_TYPE_LOCKED,
|
||||
'NEEDMANA': SOUND_TYPE_NEEDMANA,
|
||||
'NEEDSTAMINA': SOUND_TYPE_NEEDSTAMINA,
|
||||
'JUNKITEM': SOUND_TYPE_JUNKITEM,
|
||||
'LEVELGAIN': SOUND_TYPE_LEVELGAIN,
|
||||
'PICKUPITEM': SOUND_TYPE_PICKUPITEM,
|
||||
'DROPITEM': SOUND_TYPE_DROPITEM,
|
||||
'USEITEM': SOUND_TYPE_USEITEM,
|
||||
'FLEE': SOUND_TYPE_FLEE,
|
||||
'DEATH': SOUND_TYPE_DEATH,
|
||||
'INVALIDTARGET': SOUND_TYPE_INVALIDTARGET,
|
||||
'OPEN': SOUND_TYPE_OPEN,
|
||||
'CLOSE': SOUND_TYPE_CLOSE,
|
||||
'DESTROY': SOUND_TYPE_DESTROY,
|
||||
'POWERCAST': SOUND_TYPE_POWERCAST,
|
||||
'POWEREFFECT': SOUND_TYPE_POWEREFFECT,
|
||||
'POWERFAIL': SOUND_TYPE_POWERFAIL,
|
||||
'HUDOPEN': SOUND_TYPE_HUDOPEN,
|
||||
'HUDCLOSE': SOUND_TYPE_HUDCLOSE,
|
||||
'SHEATH': SOUND_TYPE_SHEATH,
|
||||
'UNSHEATH': SOUND_TYPE_UNSHEATH,
|
||||
'BUILDINGDESTROYED': SOUND_TYPE_BUILDINGDESTROYED,
|
||||
'BURN': SOUND_TYPE_BURN,
|
||||
'IDLE': SOUND_TYPE_IDLE,
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
RUNE_UNKNOWN = 0
|
||||
RUNE_RACE = 1
|
||||
RUNE_CLASS = 2
|
||||
RUNE_DISCIPLINE = 3
|
||||
RUNE_TALENT = 4
|
||||
|
||||
RUNE_TYPE_TO_STRING = {
|
||||
RUNE_UNKNOWN: 'UNKNOWN',
|
||||
RUNE_RACE: 'RACE',
|
||||
RUNE_CLASS: 'CLASS',
|
||||
RUNE_DISCIPLINE: 'DISCIPLINE',
|
||||
RUNE_TALENT: 'TALENT',
|
||||
}
|
||||
|
||||
STRING_TO_RUNE_TYPE = {
|
||||
'UNKNOWN': RUNE_UNKNOWN,
|
||||
'RACE': RUNE_RACE,
|
||||
'CLASS': RUNE_CLASS,
|
||||
'DISCIPLINE': RUNE_DISCIPLINE,
|
||||
'TALENT': RUNE_TALENT,
|
||||
}
|
||||
|
||||
SPEED_TYPE_WALK = 0
|
||||
SPEED_TYPE_RUN = 1
|
||||
SPEED_TYPE_COMBATWALK = 2
|
||||
SPEED_TYPE_COMBATRUN = 3
|
||||
SPEED_TYPE_FLYWALK = 4
|
||||
SPEED_TYPE_FLYRUN = 5
|
||||
SPEED_TYPE_SWIM = 6
|
||||
|
||||
SPEED_TYPE_TO_STRING = {
|
||||
SPEED_TYPE_WALK: 'WALK',
|
||||
SPEED_TYPE_RUN: 'RUN',
|
||||
SPEED_TYPE_COMBATWALK: 'COMBATWALK',
|
||||
SPEED_TYPE_COMBATRUN: 'COMBATRUN',
|
||||
SPEED_TYPE_FLYWALK: 'FLYWALK',
|
||||
SPEED_TYPE_FLYRUN: 'FLYRUN',
|
||||
SPEED_TYPE_SWIM: 'SWIM',
|
||||
}
|
||||
|
||||
STRING_TO_SPEED_TYPE = {
|
||||
SPEED_TYPE_WALK: 'WALK',
|
||||
SPEED_TYPE_RUN: 'RUN',
|
||||
SPEED_TYPE_COMBATWALK: 'COMBATWALK',
|
||||
SPEED_TYPE_COMBATRUN: 'COMBATRUN',
|
||||
SPEED_TYPE_FLYWALK: 'FLYWALK',
|
||||
SPEED_TYPE_FLYRUN: 'FLYRUN',
|
||||
SPEED_TYPE_SWIM: 'SWIM',
|
||||
}
|
||||
|
||||
RUNE_SEX_MALE = 1
|
||||
RUNE_SEX_FEMALE = 2
|
||||
|
||||
RUNE_SEX_TO_STRING = {
|
||||
RUNE_SEX_MALE: 'MALE',
|
||||
RUNE_SEX_FEMALE: 'FEMALE',
|
||||
}
|
||||
STRING_TO_RUNE_SEX = {
|
||||
'MALE': RUNE_SEX_MALE,
|
||||
'FEMALE': RUNE_SEX_FEMALE,
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
SPARSE_VAL_LONG = 0 # dword
|
||||
SPARSE_VAL_FLOAT = 1 # float
|
||||
SPARSE_VAL_BOOL = 2 # bool
|
||||
SPARSE_UID = 3 # dword
|
||||
SPARSE_REF_VECTOR3 = 4 # float (3)
|
||||
SPARSE_REF_ANIM_TYPE = 5 # NONE (initialize)
|
||||
SPARSE_REF_ARC_STRING = 6 # string
|
||||
SPARSE_REF_PROJECTILE_IMPACT_INFO = 7 # NONE (initialize)
|
||||
SPARSE_REF_PET_DATA = 8 # NONE (initialize)
|
||||
SPARSE_REF_MERCHANT_DATA = 9 # dword (3)
|
||||
SPARSE_REF_ARC_CACHE_ID = 10 # qword
|
||||
SPARSE_PTR_ANIM_INFO = 11 # NONE (initialize)
|
||||
SPARSE_PTR_CLIENT_ALLIANCE_MASTER = 12 # NONE (initialize)
|
||||
SPARSE_PTR_ACTION_RESPONSE = 13 # dword ???
|
||||
SPARSE_OWNED_PTR_REF_LONG = 14 # NONE (initialize)
|
||||
SPARSE_LINKED_PTR_ARC_SPELL_EFFECT = 15 # NONE (initialize)
|
||||
SPARSE_LINKED_PTR_ARC_OBJECT = 16 # NONE (initialize)
|
||||
SPARSE_LINKED_PTR_ARC_CHARACTER = 17 # NONE (initialize)
|
||||
SPARSE_ENUM_ITEM_TYPE = 18 # dword
|
||||
|
||||
SPARSE_TAG_TO_SPARSE_TYPE = {
|
||||
0xd6c9ccff: SPARSE_VAL_BOOL,
|
||||
0x974632fc: SPARSE_REF_ARC_CACHE_ID,
|
||||
0x33264efb: SPARSE_VAL_BOOL,
|
||||
0xb050a1f8: SPARSE_VAL_BOOL,
|
||||
0x74ac9ff4: SPARSE_VAL_BOOL,
|
||||
0xfa3097f3: SPARSE_VAL_LONG,
|
||||
0xfcb7daf0: SPARSE_VAL_BOOL,
|
||||
0xd3fcf8ef: SPARSE_VAL_LONG,
|
||||
0x68108be9: SPARSE_VAL_BOOL,
|
||||
0x0003eee2: SPARSE_VAL_FLOAT,
|
||||
0x9bc2dae1: SPARSE_VAL_BOOL,
|
||||
0xec0358e0: SPARSE_REF_PET_DATA,
|
||||
0x0ebddedc: SPARSE_VAL_BOOL,
|
||||
0x4b9bffe9: SPARSE_VAL_BOOL,
|
||||
0x632720d3: SPARSE_VAL_BOOL,
|
||||
0x4ec9a98b: SPARSE_VAL_LONG,
|
||||
0x001215cd: SPARSE_UID,
|
||||
0xf0e64dcb: SPARSE_VAL_BOOL,
|
||||
0x19fe50c4: SPARSE_VAL_LONG,
|
||||
0x79933e68: SPARSE_VAL_BOOL,
|
||||
0xce9332c2: SPARSE_VAL_BOOL,
|
||||
0x016e5bbc: SPARSE_LINKED_PTR_ARC_CHARACTER,
|
||||
0x7c4c10bb: SPARSE_VAL_BOOL,
|
||||
0x164018ba: SPARSE_REF_ARC_CACHE_ID,
|
||||
0x81b3a0b8: SPARSE_VAL_LONG,
|
||||
0xdb45b0b6: SPARSE_VAL_BOOL,
|
||||
0xcfbf3912: SPARSE_LINKED_PTR_ARC_SPELL_EFFECT,
|
||||
0xb1ebd7af: SPARSE_VAL_BOOL,
|
||||
0xfb5a0fae: SPARSE_VAL_BOOL,
|
||||
0x86b3f6ac: SPARSE_VAL_BOOL,
|
||||
0xec9375a5: SPARSE_REF_ARC_CACHE_ID,
|
||||
0xdce49ee0: SPARSE_VAL_BOOL,
|
||||
0xef28bc61: SPARSE_VAL_LONG,
|
||||
0xed365292: SPARSE_REF_ARC_CACHE_ID,
|
||||
0x247a9c91: SPARSE_REF_ARC_STRING,
|
||||
0x9c57a38f: SPARSE_REF_ARC_CACHE_ID,
|
||||
0xd41c4373: SPARSE_VAL_BOOL,
|
||||
0x56c43c4a: SPARSE_VAL_BOOL,
|
||||
0x9b816e84: SPARSE_VAL_BOOL,
|
||||
0xc973df7b: SPARSE_VAL_BOOL,
|
||||
0xe5919779: SPARSE_VAL_LONG,
|
||||
0xac494477: SPARSE_VAL_BOOL,
|
||||
0x0513cb74: SPARSE_ENUM_ITEM_TYPE,
|
||||
0x0f13b873: SPARSE_VAL_FLOAT,
|
||||
0xeec1c470: SPARSE_VAL_BOOL,
|
||||
0x18edb06b: SPARSE_PTR_ANIM_INFO,
|
||||
0x90493768: SPARSE_REF_ARC_STRING,
|
||||
0xc231f466: SPARSE_VAL_BOOL,
|
||||
0x5dd6d263: SPARSE_VAL_FLOAT,
|
||||
0xa074b062: SPARSE_VAL_LONG,
|
||||
0xc9033661: SPARSE_REF_ARC_CACHE_ID,
|
||||
0x5de60660: SPARSE_REF_ARC_STRING,
|
||||
0x2778c65e: SPARSE_REF_MERCHANT_DATA,
|
||||
0x7add7b5b: SPARSE_REF_VECTOR3,
|
||||
0xa0736056: SPARSE_REF_VECTOR3,
|
||||
0x192fbb63: SPARSE_VAL_BOOL,
|
||||
0xa2e74b50: SPARSE_VAL_LONG,
|
||||
0xf3c4b6b2: SPARSE_VAL_BOOL,
|
||||
0x2395a34a: SPARSE_VAL_BOOL,
|
||||
0xbb0b3547: SPARSE_VAL_BOOL,
|
||||
0xf95e662c: SPARSE_PTR_ACTION_RESPONSE,
|
||||
0xf7638542: SPARSE_VAL_BOOL,
|
||||
0xb347c33f: SPARSE_VAL_BOOL,
|
||||
0x4052ed3a: SPARSE_LINKED_PTR_ARC_OBJECT,
|
||||
0x76be8439: SPARSE_VAL_BOOL,
|
||||
0x0c684d37: SPARSE_REF_MERCHANT_DATA,
|
||||
0xadeb5733: SPARSE_VAL_BOOL,
|
||||
0xc8c49031: SPARSE_VAL_BOOL,
|
||||
0xa5e4ee2f: SPARSE_VAL_LONG,
|
||||
0xe41fc02d: SPARSE_PTR_CLIENT_ALLIANCE_MASTER,
|
||||
0xcf26f82c: SPARSE_VAL_BOOL,
|
||||
0xee8afac4: SPARSE_VAL_BOOL,
|
||||
0xfca1c13f: SPARSE_VAL_BOOL,
|
||||
0x5bfed2e0: SPARSE_REF_ANIM_TYPE,
|
||||
0x99454720: SPARSE_VAL_BOOL,
|
||||
0xdcf35c1b: SPARSE_UID,
|
||||
0x8c232316: SPARSE_VAL_BOOL,
|
||||
0xd8abfa13: SPARSE_VAL_LONG,
|
||||
0x16398a12: SPARSE_VAL_BOOL,
|
||||
0xbb7dcd11: SPARSE_VAL_BOOL,
|
||||
0x938c185b: SPARSE_VAL_BOOL,
|
||||
0xffad4f07: SPARSE_VAL_LONG,
|
||||
0xd37af906: SPARSE_OWNED_PTR_REF_LONG,
|
||||
0x35b3682c: SPARSE_REF_PROJECTILE_IMPACT_INFO,
|
||||
0x866d4200: SPARSE_VAL_BOOL,
|
||||
}
|
||||
|
||||
SPARSE_TAG_TO_STRING = {
|
||||
0xd6c9ccff: 'GoalDirection',
|
||||
0x974632fc: 'oldGuildID',
|
||||
0x33264efb: 'ADMIN_CAN_GUILDWHO',
|
||||
0xb050a1f8: 'ADMIN_CAN_SHUTDOWNSERVER',
|
||||
0x74ac9ff4: 'ADMIN_CAN_DISCONNECTPLAYERS',
|
||||
0xfa3097f3: 'ADMIN_SNOOPLEVEL',
|
||||
0xfcb7daf0: 'ADMIN_CAN_DELETEUSER',
|
||||
0xd3fcf8ef: 'GEN_TABLE_ID',
|
||||
0x68108be9: 'ADMIN_CAN_TELEPORT',
|
||||
0x0003eee2: 'buy%',
|
||||
0x9bc2dae1: 'ADMIN_CAN_LOCATE',
|
||||
0xec0358e0: 'petData',
|
||||
0x0ebddedc: 'ADMIN_CAN_SET_DECAY',
|
||||
0x4b9bffe9: 'ADMIN_CAN_ZONE',
|
||||
0x632720d3: 'PGOV_PLAYER',
|
||||
0x4ec9a98b: 'ADMIN_REMOVEEQUIPMENTEFFECTSLEVEL',
|
||||
0x001215cd: 'MODE',
|
||||
0xf0e64dcb: 'ADMIN_IS_WORLDBUILDER',
|
||||
0x19fe50c4: 'trainerSkillCost',
|
||||
0x79933e68: 'ADMIN_CAN_MODIFYUSER',
|
||||
0xce9332c2: 'shopkeeper',
|
||||
0x016e5bbc: 'PeekTarget',
|
||||
0x7c4c10bb: 'IS_ANNOUNCED_ITEM',
|
||||
0x164018ba: 'DISC_PROMOTION_RUNEID',
|
||||
0x81b3a0b8: 'ADMIN_TOKENREADACCESSLEVEL',
|
||||
0xdb45b0b6: 'ADMIN_CAN_ACCESSPETITIONSYSTEM',
|
||||
0xcfbf3912: 'SpellEffect',
|
||||
0xb1ebd7af: 'ADMIN_CAN_UPLOADMOTD',
|
||||
0xfb5a0fae: 'ADMIN_IS_INVULNERABLE',
|
||||
0x86b3f6ac: 'ADMIN_CAN_PURGE',
|
||||
0xec9375a5: 'oldNationID',
|
||||
0xdce49ee0: 'ADMIN_CAN_DELETECHARACTER',
|
||||
0xef28bc61: 'MAX_POWER_LEVEL',
|
||||
0xed365292: 'liveInstanceID',
|
||||
0x247a9c91: 'ROOTFSMID',
|
||||
0x9c57a38f: 'ITEMTOREPLACE',
|
||||
0xd41c4373: 'ADMIN_CAN_TELEPORTOTHER',
|
||||
0x56c43c4a: 'isMinion',
|
||||
0x9b816e84: 'ADMIN_CAN_POSSESS',
|
||||
0xc973df7b: 'ADMIN_CAN_RECEIVE_TELLS',
|
||||
0xe5919779: 'ADMIN_ACCESSLEVEL',
|
||||
0xac494477: 'wasPet',
|
||||
0x0513cb74: 'types',
|
||||
0x0f13b873: 'sales%',
|
||||
0xeec1c470: 'ADMIN_CAN_GETINFO',
|
||||
0x18edb06b: 'altAttackAnims',
|
||||
0x90493768: 'shopFile',
|
||||
0xc231f466: 'IMMUNE_TO_STEAL',
|
||||
0x5dd6d263: 'charOrientation',
|
||||
0xa074b062: 'banker',
|
||||
0xc9033661: 'CLASS_PROMOTION_RUNEID',
|
||||
0x5de60660: 'ACTIONMESSAGE',
|
||||
0x2778c65e: 'merchantData',
|
||||
0x7add7b5b: 'charLocation',
|
||||
0xa0736056: 'WanderDir',
|
||||
0x192fbb63: 'CharMarkedForDelete',
|
||||
0xa2e74b50: 'expLost',
|
||||
0xf3c4b6b2: 'ADMIN_ISWOLFPACKDEV',
|
||||
0x2395a34a: 'WaitingInvite',
|
||||
0xbb0b3547: 'ADMIN_CAN_GETINVENTORY',
|
||||
0xf95e662c: 'ACTIONRESPONSE',
|
||||
0xf7638542: 'ADMIN_CAN_SETINVULNERABLE',
|
||||
0xb347c33f: 'ADMIN_CAN_TRANSFER',
|
||||
0x4052ed3a: 'trackingArrow',
|
||||
0x76be8439: 'ADMIN_CAN_SUMMON',
|
||||
0x0c684d37: 'GuardData',
|
||||
0xadeb5733: 'ADMIN_CAN_OBJECTEDIT',
|
||||
0xc8c49031: 'ADMIN_ISADMIN',
|
||||
0xa5e4ee2f: 'ADMIN_CHANNELACCESSLEVEL',
|
||||
0xe41fc02d: 'ClientAllianceMaster',
|
||||
0xcf26f82c: 'ADMIN_CAN_TELL_ADMIN',
|
||||
0xee8afac4: 'ADMIN_CAN_SETSTAT',
|
||||
0xfca1c13f: 'ADMIN_IS_GUILDGODADMIN',
|
||||
0x5bfed2e0: 'BladeTrailAnims',
|
||||
0x99454720: 'CAN_ENTER_COMBAT',
|
||||
0xdcf35c1b: 'ADMIN_IP_RESTRICTION',
|
||||
0x8c232316: 'ADMIN_CAN_USE_ITEM_WIZ',
|
||||
0xd8abfa13: 'ADMIN_TOKENWRITEACCESSLEVEL',
|
||||
0x16398a12: 'isTrainer',
|
||||
0xbb7dcd11: 'ADMIN_CAN_SUMMONCORPSE',
|
||||
0x938c185b: 'CAN_PICKUPANDDROPITEMS',
|
||||
0xffad4f07: 'ADMIN_REMOVEPOWEREFFECTSLEVEL',
|
||||
0xd37af906: 'merchantOptions',
|
||||
0x35b3682c: 'projectileImpactInfo',
|
||||
0x866d4200: 'ADMIN_CAN_TRANSFORM_RACE',
|
||||
}
|
||||
|
||||
STRING_TO_SPARSE_TAG = {
|
||||
'GoalDirection': 0xd6c9ccff,
|
||||
'oldGuildID': 0x974632fc,
|
||||
'ADMIN_CAN_GUILDWHO': 0x33264efb,
|
||||
'ADMIN_CAN_SHUTDOWNSERVER': 0xb050a1f8,
|
||||
'ADMIN_CAN_DISCONNECTPLAYERS': 0x74ac9ff4,
|
||||
'ADMIN_SNOOPLEVEL': 0xfa3097f3,
|
||||
'ADMIN_CAN_DELETEUSER': 0xfcb7daf0,
|
||||
'GEN_TABLE_ID': 0xd3fcf8ef,
|
||||
'ADMIN_CAN_TELEPORT': 0x68108be9,
|
||||
'buy%': 0x0003eee2,
|
||||
'ADMIN_CAN_LOCATE': 0x9bc2dae1,
|
||||
'petData': 0xec0358e0,
|
||||
'ADMIN_CAN_SET_DECAY': 0x0ebddedc,
|
||||
'ADMIN_CAN_ZONE': 0x4b9bffe9,
|
||||
'PGOV_PLAYER': 0x632720d3,
|
||||
'ADMIN_REMOVEEQUIPMENTEFFECTSLEVEL': 0x4ec9a98b,
|
||||
'MODE': 0x001215cd,
|
||||
'ADMIN_IS_WORLDBUILDER': 0xf0e64dcb,
|
||||
'trainerSkillCost': 0x19fe50c4,
|
||||
'ADMIN_CAN_MODIFYUSER': 0x79933e68,
|
||||
'shopkeeper': 0xce9332c2,
|
||||
'PeekTarget': 0x016e5bbc,
|
||||
'IS_ANNOUNCED_ITEM': 0x7c4c10bb,
|
||||
'DISC_PROMOTION_RUNEID': 0x164018ba,
|
||||
'ADMIN_TOKENREADACCESSLEVEL': 0x81b3a0b8,
|
||||
'ADMIN_CAN_ACCESSPETITIONSYSTEM': 0xdb45b0b6,
|
||||
'SpellEffect': 0xcfbf3912,
|
||||
'ADMIN_CAN_UPLOADMOTD': 0xb1ebd7af,
|
||||
'ADMIN_IS_INVULNERABLE': 0xfb5a0fae,
|
||||
'ADMIN_CAN_PURGE': 0x86b3f6ac,
|
||||
'oldNationID': 0xec9375a5,
|
||||
'ADMIN_CAN_DELETECHARACTER': 0xdce49ee0,
|
||||
'MAX_POWER_LEVEL': 0xef28bc61,
|
||||
'liveInstanceID': 0xed365292,
|
||||
'ROOTFSMID': 0x247a9c91,
|
||||
'ITEMTOREPLACE': 0x9c57a38f,
|
||||
'ADMIN_CAN_TELEPORTOTHER': 0xd41c4373,
|
||||
'isMinion': 0x56c43c4a,
|
||||
'ADMIN_CAN_POSSESS': 0x9b816e84,
|
||||
'ADMIN_CAN_RECEIVE_TELLS': 0xc973df7b,
|
||||
'ADMIN_ACCESSLEVEL': 0xe5919779,
|
||||
'wasPet': 0xac494477,
|
||||
'types': 0x0513cb74,
|
||||
'sales%': 0x0f13b873,
|
||||
'ADMIN_CAN_GETINFO': 0xeec1c470,
|
||||
'altAttackAnims': 0x18edb06b,
|
||||
'shopFile': 0x90493768,
|
||||
'IMMUNE_TO_STEAL': 0xc231f466,
|
||||
'charOrientation': 0x5dd6d263,
|
||||
'banker': 0xa074b062,
|
||||
'CLASS_PROMOTION_RUNEID': 0xc9033661,
|
||||
'ACTIONMESSAGE': 0x5de60660,
|
||||
'merchantData': 0x2778c65e,
|
||||
'charLocation': 0x7add7b5b,
|
||||
'WanderDir': 0xa0736056,
|
||||
'CharMarkedForDelete': 0x192fbb63,
|
||||
'expLost': 0xa2e74b50,
|
||||
'ADMIN_ISWOLFPACKDEV': 0xf3c4b6b2,
|
||||
'WaitingInvite': 0x2395a34a,
|
||||
'ADMIN_CAN_GETINVENTORY': 0xbb0b3547,
|
||||
'ACTIONRESPONSE': 0xf95e662c,
|
||||
'ADMIN_CAN_SETINVULNERABLE': 0xf7638542,
|
||||
'ADMIN_CAN_TRANSFER': 0xb347c33f,
|
||||
'trackingArrow': 0x4052ed3a,
|
||||
'ADMIN_CAN_SUMMON': 0x76be8439,
|
||||
'GuardData': 0x0c684d37,
|
||||
'ADMIN_CAN_OBJECTEDIT': 0xadeb5733,
|
||||
'ADMIN_ISADMIN': 0xc8c49031,
|
||||
'ADMIN_CHANNELACCESSLEVEL': 0xa5e4ee2f,
|
||||
'ClientAllianceMaster': 0xe41fc02d,
|
||||
'ADMIN_CAN_TELL_ADMIN': 0xcf26f82c,
|
||||
'ADMIN_CAN_SETSTAT': 0xee8afac4,
|
||||
'ADMIN_IS_GUILDGODADMIN': 0xfca1c13f,
|
||||
'BladeTrailAnims': 0x5bfed2e0,
|
||||
'CAN_ENTER_COMBAT': 0x99454720,
|
||||
'ADMIN_IP_RESTRICTION': 0xdcf35c1b,
|
||||
'ADMIN_CAN_USE_ITEM_WIZ': 0x8c232316,
|
||||
'ADMIN_TOKENWRITEACCESSLEVEL': 0xd8abfa13,
|
||||
'isTrainer': 0x16398a12,
|
||||
'ADMIN_CAN_SUMMONCORPSE': 0xbb7dcd11,
|
||||
'CAN_PICKUPANDDROPITEMS': 0x938c185b,
|
||||
'ADMIN_REMOVEPOWEREFFECTSLEVEL': 0xffad4f07,
|
||||
'merchantOptions': 0xd37af906,
|
||||
'projectileImpactInfo': 0x35b3682c,
|
||||
'ADMIN_CAN_TRANSFORM_RACE': 0x866d4200,
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
REGION_CONTENTBEHAVIOR_SHOWNONE = 0
|
||||
REGION_CONTENTBEHAVIOR_SHOWCHARACTERS = 1
|
||||
REGION_CONTENTBEHAVIOR_SHOWOBJECTS = 2
|
||||
REGION_CONTENTBEHAVIOR_SHOWALL = 3
|
||||
|
||||
REGION_CONTENTBEHAVIOR_TO_STRING = {
|
||||
REGION_CONTENTBEHAVIOR_SHOWNONE: 'SHOWNONE',
|
||||
REGION_CONTENTBEHAVIOR_SHOWCHARACTERS: 'SHOWCHARACTERS',
|
||||
REGION_CONTENTBEHAVIOR_SHOWOBJECTS: 'SHOWOBJECTS',
|
||||
REGION_CONTENTBEHAVIOR_SHOWALL: 'SHOWALL',
|
||||
}
|
||||
|
||||
STRING_TO_REGION_CONTENTBEHAVIOR = {
|
||||
'SHOWNONE': REGION_CONTENTBEHAVIOR_SHOWNONE,
|
||||
'SHOWCHARACTERS': REGION_CONTENTBEHAVIOR_SHOWCHARACTERS,
|
||||
'SHOWOBJECTS': REGION_CONTENTBEHAVIOR_SHOWOBJECTS,
|
||||
'SHOWALL': REGION_CONTENTBEHAVIOR_SHOWALL,
|
||||
}
|
||||
|
||||
REGION_STATE_INSIDE = 1
|
||||
REGION_STATE_OUTSIDE = 2
|
||||
|
||||
REGION_STATE_TO_STRING = {
|
||||
REGION_STATE_INSIDE: 'INSIDE',
|
||||
REGION_STATE_OUTSIDE: 'OUTSIDE',
|
||||
}
|
||||
|
||||
STRING_TO_REGION_STATE = {
|
||||
'INSIDE': REGION_STATE_INSIDE,
|
||||
'OUTSIDE': REGION_STATE_OUTSIDE,
|
||||
}
|
||||
|
||||
LEVEL_TYPE_EXTERIOR = False
|
||||
LEVEL_TYPE_INTERIOR = True
|
||||
|
||||
LEVEL_TYPE_TO_STRING = {
|
||||
LEVEL_TYPE_EXTERIOR: 'EXTERIOR',
|
||||
LEVEL_TYPE_INTERIOR: 'INTERIOR',
|
||||
}
|
||||
|
||||
STRING_TO_LEVEL_TYPE = {
|
||||
'EXTERIOR': LEVEL_TYPE_EXTERIOR,
|
||||
'INTERIOR': LEVEL_TYPE_INTERIOR,
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
@@ -0,0 +1,23 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
INVENTORY_TYPE_GOLD = 1
|
||||
INVENTORY_TYPE_ITEM = 2
|
||||
INVENTORY_TYPE_BOOTYTABLE = 3
|
||||
|
||||
INVENTORY_TYPE_TO_STRING = {
|
||||
INVENTORY_TYPE_GOLD: 'GOLD',
|
||||
INVENTORY_TYPE_ITEM: 'ITEM',
|
||||
INVENTORY_TYPE_BOOTYTABLE: 'BOOTYTABLE',
|
||||
}
|
||||
|
||||
STRING_TO_INVENTORY_TYPE = {
|
||||
'GOLD': INVENTORY_TYPE_GOLD,
|
||||
'ITEM': INVENTORY_TYPE_ITEM,
|
||||
'BOOTYTABLE': INVENTORY_TYPE_BOOTYTABLE,
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
import glob
|
||||
import os
|
||||
|
||||
from arcane.util.hasher import hash_string
|
||||
|
||||
_STRING_TO_HASH = {}
|
||||
_HASH_TO_STRING = {}
|
||||
|
||||
|
||||
def load_files():
|
||||
directory = os.path.dirname(__file__)
|
||||
|
||||
for filepath in glob.glob(os.path.join(directory, '*.txt')):
|
||||
lines = list(map(lambda s: s.strip(), open(filepath).readlines()))
|
||||
|
||||
_STRING_TO_HASH.update({
|
||||
s: hash_string(s) for s in lines
|
||||
})
|
||||
|
||||
_HASH_TO_STRING.update({
|
||||
hash_string(s): s for s in lines
|
||||
})
|
||||
|
||||
|
||||
def string_to_hash(s):
|
||||
return _STRING_TO_HASH.get(s, s)
|
||||
|
||||
|
||||
def hash_to_string(h):
|
||||
return _HASH_TO_STRING.get(h, h)
|
||||
|
||||
|
||||
load_files()
|
||||
@@ -0,0 +1,5 @@
|
||||
Strength
|
||||
Dexterity
|
||||
Constitution
|
||||
Intelligence
|
||||
Spirit
|
||||
@@ -0,0 +1,27 @@
|
||||
Fighter
|
||||
Healer
|
||||
Rogue
|
||||
Mage
|
||||
Warrior
|
||||
Priest
|
||||
Thief
|
||||
Wizard
|
||||
Assassin
|
||||
Barbarian
|
||||
Bard
|
||||
Channeler
|
||||
Confessor
|
||||
Crusader
|
||||
Druid
|
||||
Fury
|
||||
Huntress
|
||||
Pet
|
||||
Prelate
|
||||
Ranger
|
||||
Scout
|
||||
Templar
|
||||
Warlock
|
||||
Doomsayer
|
||||
Sentinel
|
||||
Necromancer
|
||||
Nightstalker
|
||||
@@ -0,0 +1,51 @@
|
||||
Alchemist
|
||||
Animator
|
||||
Archer
|
||||
Berserker
|
||||
Black Mask
|
||||
Blacksmith
|
||||
Blade Master
|
||||
Blade Weaver
|
||||
Blood Prophet
|
||||
Bounty Hunter
|
||||
Clanwarden
|
||||
Commander
|
||||
Dark Knight
|
||||
Duelist
|
||||
Forge Master
|
||||
Giant Killer
|
||||
Gladiator
|
||||
Huntsman
|
||||
Knight
|
||||
Rat Catcher
|
||||
Rune Caster
|
||||
Enchanter
|
||||
Storm Lord
|
||||
Summoner
|
||||
Sundancer
|
||||
Trainer
|
||||
Traveler
|
||||
Undead Hunter
|
||||
Werebear
|
||||
Wererat
|
||||
Werewolf
|
||||
Wyrmslayer
|
||||
Conjurer
|
||||
Darksworn
|
||||
Valkyr
|
||||
Blood Horn
|
||||
Shroudborne
|
||||
Archmage
|
||||
Thrall
|
||||
Artillerist
|
||||
Savant
|
||||
Sky Dancer
|
||||
Prospector
|
||||
Belgosch
|
||||
Drannok
|
||||
Gorgoi
|
||||
Strigoi
|
||||
Sapper
|
||||
Saboteur
|
||||
Battle Magus
|
||||
Sanctifier
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,13 @@
|
||||
BaseSky
|
||||
ChaosSky
|
||||
ChaosAltSky
|
||||
Dead
|
||||
DesertSky
|
||||
ElfSky
|
||||
Joe Cool
|
||||
NorthlandsSky
|
||||
Storm01
|
||||
Storm02
|
||||
Storm03
|
||||
SwampSky
|
||||
WastelandSky
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,35 @@
|
||||
Aelfborn
|
||||
All
|
||||
Animal
|
||||
Aracoix
|
||||
Celestial
|
||||
Centaur
|
||||
Construct
|
||||
CSR
|
||||
Dragon
|
||||
Dwarf
|
||||
Elf
|
||||
Giant
|
||||
Goblin
|
||||
Grave
|
||||
Half-Giant
|
||||
Human
|
||||
Infernal
|
||||
Insect
|
||||
Irekei
|
||||
Minotaur
|
||||
Monster
|
||||
NecroPet
|
||||
NPC
|
||||
Pet
|
||||
Plant
|
||||
Rat
|
||||
Reptile
|
||||
Shade
|
||||
Siege
|
||||
Summoned
|
||||
Troll
|
||||
Undead
|
||||
Nephilim
|
||||
Vampire
|
||||
SiegeEngineer
|
||||
@@ -0,0 +1,23 @@
|
||||
Gold
|
||||
Stone
|
||||
Truesteel
|
||||
Iron
|
||||
Adamant
|
||||
Lumber
|
||||
Oak
|
||||
Bronzewood
|
||||
Mandrake
|
||||
Coal
|
||||
Agate
|
||||
Diamond
|
||||
Onyx
|
||||
Azoth
|
||||
Orichalk
|
||||
Antimony
|
||||
Sulfur
|
||||
Quicksilver
|
||||
Galvor
|
||||
Wormwood
|
||||
Obsidian
|
||||
Bloodstone
|
||||
Mithril
|
||||
@@ -0,0 +1,94 @@
|
||||
Animation
|
||||
Archery
|
||||
Athletics
|
||||
Axe Mastery
|
||||
Axe
|
||||
Bardsong
|
||||
Bargaining
|
||||
Beastcraft
|
||||
Benediction
|
||||
Blade Mastery
|
||||
Blade Weaving
|
||||
Block
|
||||
Bow
|
||||
Channeling
|
||||
Cloth
|
||||
Conditioning
|
||||
Crossbow
|
||||
Dagger Mastery
|
||||
Dagger
|
||||
Dodge
|
||||
Dueling
|
||||
Enchantment
|
||||
Endurance
|
||||
Flame Calling
|
||||
Focus
|
||||
Great Axe Mastery
|
||||
Great Hammer Mastery
|
||||
Great Sword Mastery
|
||||
Hammer Mastery
|
||||
Hammer
|
||||
Leadership
|
||||
Learning
|
||||
Liturgy
|
||||
Meditation
|
||||
Nature Lore
|
||||
None
|
||||
Opening
|
||||
Parry
|
||||
Pole Arm Mastery
|
||||
Pole Arm
|
||||
Resistance, Acid
|
||||
Resistance, Cold
|
||||
Resistance, Crushing
|
||||
Resistance, Disease
|
||||
Resistance, Earth
|
||||
Resistance, Fire
|
||||
Resistance, Holy
|
||||
Resistance, Lightning
|
||||
Resistance, Magic
|
||||
Resistance, Mental
|
||||
Resistance, Piercing
|
||||
Resistance, Poison
|
||||
Resistance, Slashing
|
||||
Resistance, Unholy
|
||||
Restoration
|
||||
Runecarving
|
||||
Running
|
||||
Shadowmastery
|
||||
Shapechanging
|
||||
Sorcery
|
||||
Spear Mastery
|
||||
Spear
|
||||
Staff Mastery
|
||||
Staff
|
||||
Stormcalling
|
||||
Subterfuge
|
||||
Summoning
|
||||
Sword Mastery
|
||||
Sword
|
||||
Thaumaturgy
|
||||
Theurgy
|
||||
Throwing
|
||||
Toughness
|
||||
Unarmed Combat Mastery
|
||||
Unarmed Combat
|
||||
Unknown
|
||||
Warding
|
||||
Warlockry
|
||||
Way of the Gaana
|
||||
Wear Armor, Heavy
|
||||
Wear Armor, Light
|
||||
Wear Armor, Medium
|
||||
Willpower
|
||||
Wizardry
|
||||
Corruption
|
||||
Abjuration
|
||||
Way of the Wolf
|
||||
Way of the Rat
|
||||
Way of the Bear
|
||||
Orthanatos
|
||||
Bloodcraft
|
||||
Exorcism
|
||||
Necromancy
|
||||
Sun Dancing
|
||||
@@ -0,0 +1,132 @@
|
||||
ALLIGATOR
|
||||
ARACOIX_FEMALE
|
||||
ARACOIX_FEMALE_NPC
|
||||
ARACOIX_MALE
|
||||
ARACOIX_MALE_NPC
|
||||
ARACOIX_SKELETAL
|
||||
ARCHON
|
||||
BALLISTA
|
||||
BANSHEE
|
||||
BAT_VAMPIRE
|
||||
BEAR
|
||||
BEASTMAN_BAT
|
||||
BEASTMAN_BEAR
|
||||
BEASTMAN_WOLF
|
||||
BEASTMAN_WOLVERINE
|
||||
BOVINE
|
||||
CAMEL
|
||||
CAT
|
||||
CAT_COUGAR
|
||||
CENTIPEDE
|
||||
DEER
|
||||
DEMON_FEMALE
|
||||
DEMON01
|
||||
DEMON02
|
||||
DJINNI
|
||||
DOG
|
||||
DRAKE
|
||||
DRAKE_SKELETAL
|
||||
DRAKE_WYRM
|
||||
DWARF
|
||||
DWARF_NPC
|
||||
EAGLE
|
||||
ELEMENTAL_AIR
|
||||
ELEMENTAL_EARTH
|
||||
ELEMENTAL_FIRE
|
||||
ELEMENTAL_WATER
|
||||
ELEPHANT
|
||||
ELF_FEMALE
|
||||
ELF_FEMALE_NPC
|
||||
ELF_MALE
|
||||
ELF_MALE_NPC
|
||||
ETTIN
|
||||
FROG
|
||||
GARGOYLE
|
||||
GAUNT
|
||||
GHOUL
|
||||
GIANT
|
||||
GIANT_SPRIGGAN
|
||||
GIANT_STORM
|
||||
GIANT_SWAMP
|
||||
GOAT
|
||||
GOBLIN
|
||||
GOLEM_FLESH
|
||||
GOLEM_IRON
|
||||
GOLEM_STONE
|
||||
GORILLA
|
||||
GRIFFIN
|
||||
GRUB
|
||||
HAG
|
||||
HARPY
|
||||
HAWK
|
||||
HORSE
|
||||
HUMAN_CRAZED_FEMALE
|
||||
HUMAN_CRAZED_MALE
|
||||
HUMAN_EVIL_FEMALE
|
||||
HUMAN_EVIL_MALE
|
||||
HUMAN_FEMALE
|
||||
HUMAN_FEMALE_CRAZED
|
||||
HUMAN_FEMALE_EVIL
|
||||
HUMAN_FEMALE_NPC
|
||||
HUMAN_MALE
|
||||
HUMAN_MALE_CRAZED
|
||||
HUMAN_MALE_EVIL
|
||||
HUMAN_MALE_NPC
|
||||
HYDRA
|
||||
IREKEI_FEMALE
|
||||
IREKEI_FEMALE_NPC
|
||||
IREKEI_MALE
|
||||
IREKEI_MALE_NPC
|
||||
LEVIATHAN
|
||||
LIZARDMAN
|
||||
LOON
|
||||
MANGONEL
|
||||
MINOTAUR
|
||||
MINOTAUR_NPC
|
||||
MINOTAUR_SKELETAL
|
||||
MOSSMAN
|
||||
MUMMY
|
||||
NEPHILIM_FEMALE
|
||||
NEPHILIM_MALE
|
||||
OBLIVION_GHOUL
|
||||
OGRE
|
||||
ORC
|
||||
OWL
|
||||
PEACOCK
|
||||
PIG
|
||||
PLANT_GAS
|
||||
PLANT_RIPPER
|
||||
PLANT_SPITTER
|
||||
RAT
|
||||
RAVEN
|
||||
RHINO
|
||||
RUKUVHO
|
||||
SHADE_FEMALE
|
||||
SHADE_FEMALE_NPC
|
||||
SHADE_MALE
|
||||
SHADE_MALE_NPC
|
||||
SIEGE
|
||||
SKELETAL_HOUND
|
||||
SKELETON
|
||||
SKRELL
|
||||
SNAKE
|
||||
SPIDER
|
||||
SUCCUBUS
|
||||
SUCUBUS
|
||||
TIGER
|
||||
TREANT
|
||||
TREBUCHET
|
||||
TROLL
|
||||
UNDEAD_FEMALE
|
||||
VAMPIRE_FEMALE
|
||||
VAMPIRE_FEMALE_NPC
|
||||
VAMPIRE_MALE
|
||||
VAMPIRE_MALE_NPC
|
||||
VAMPIRE_NOBLE
|
||||
VULTURE
|
||||
WALRUS
|
||||
WOLF
|
||||
WRAITH
|
||||
WYVERN
|
||||
YETI
|
||||
ZOMBIE
|
||||
@@ -0,0 +1,22 @@
|
||||
Admin
|
||||
Nightvision
|
||||
Ambidexterity
|
||||
SpiMaxIncrease
|
||||
DexMaxIncrease
|
||||
ConMaxIncrease
|
||||
StrMaxIncrease
|
||||
StamMaxIncrease
|
||||
IntMaxIncrease
|
||||
HealthMaxIncrease
|
||||
ManaMaxIncrease
|
||||
Background
|
||||
Mentor
|
||||
Apprentice
|
||||
Blood Gift
|
||||
Childhood
|
||||
Constitution
|
||||
Dexterity
|
||||
Intelligence
|
||||
Spirit
|
||||
Strength
|
||||
Subrace
|
||||
@@ -0,0 +1,22 @@
|
||||
Acid Rain
|
||||
Ash
|
||||
Blizzard
|
||||
Blood Rain
|
||||
Chaos Acid Rain
|
||||
Chaos Ash
|
||||
Chaos Blood Rain
|
||||
Heavy Rain
|
||||
Rain
|
||||
Snow
|
||||
BasicRain
|
||||
BasicSleet
|
||||
BasicSnow
|
||||
STANDARDRAIN
|
||||
BLACK RAIN
|
||||
STANDARDWIND
|
||||
BLACK SNOW
|
||||
BLIZZARD
|
||||
MIST
|
||||
SNOW
|
||||
StandardSnow
|
||||
StandardSleet
|
||||
@@ -0,0 +1,38 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
MOBILE = 1
|
||||
BANKER = 2
|
||||
SHOPKEEPER = 3
|
||||
TRAINER = 4
|
||||
MERCHANT = 8
|
||||
HIRELING = 9
|
||||
PET = 10
|
||||
MINION = 11
|
||||
|
||||
MOBILE_TO_STRING = {
|
||||
MOBILE: 'MOBILE',
|
||||
BANKER: 'BANKER',
|
||||
SHOPKEEPER: 'SHOPKEEPER',
|
||||
TRAINER: 'TRAINER',
|
||||
MERCHANT: 'MERCHANT',
|
||||
HIRELING: 'HIRELING',
|
||||
PET: 'PET',
|
||||
MINION: 'MINION',
|
||||
}
|
||||
|
||||
STRING_TO_MOBILE = {
|
||||
'MOBILE': MOBILE,
|
||||
'BANKER': BANKER,
|
||||
'SHOPKEEPER': SHOPKEEPER,
|
||||
'TRAINER': TRAINER,
|
||||
'MERCHANT': MERCHANT,
|
||||
'HIRELING': HIRELING,
|
||||
'PET': PET,
|
||||
'MINION': MINION,
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
PROP = 5
|
||||
CITY = 6
|
||||
CONTAINER = 7
|
||||
|
||||
PROP_TO_STRING = {
|
||||
PROP: 'PROP',
|
||||
CITY: 'CITY',
|
||||
CONTAINER: 'CONTAINER',
|
||||
}
|
||||
|
||||
STRING_TO_PROP = {
|
||||
'PROP': PROP,
|
||||
'CITY': CITY,
|
||||
'CONTAINER': CONTAINER,
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
PEAKED = 1
|
||||
RIDGED = 2
|
||||
ROLLING = 3
|
||||
MESA = 5
|
||||
PLANAR = 4
|
||||
MESH = 6
|
||||
TARGA = 7
|
||||
|
||||
TERRAIN_TYPE_TO_STRING = {
|
||||
PEAKED: 'PEAKED',
|
||||
RIDGED: 'RIDGED',
|
||||
ROLLING: 'ROLLING',
|
||||
MESA: 'MESA',
|
||||
PLANAR: 'PLANAR',
|
||||
MESH: 'MESH',
|
||||
TARGA: 'TARGA',
|
||||
}
|
||||
|
||||
STRING_TO_TERRAIN_TYPE = {
|
||||
'PEAKED': PEAKED,
|
||||
'RIDGED': RIDGED,
|
||||
'ROLLING': ROLLING,
|
||||
'MESA': MESA,
|
||||
'PLANAR': PLANAR,
|
||||
'MESH': MESH,
|
||||
'TARGA': TARGA,
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
ELLIPTICAL = 0
|
||||
RECTANGULAR = 1
|
||||
|
||||
ZONE_TO_STRING = {
|
||||
ELLIPTICAL: 'ELLIPTICAL',
|
||||
RECTANGULAR: 'RECTANGULAR',
|
||||
}
|
||||
|
||||
STRING_TO_ZONE = {
|
||||
'ELLIPTICAL': ELLIPTICAL,
|
||||
'RECTANGULAR': RECTANGULAR,
|
||||
}
|
||||
|
||||
GLOBAL = 0
|
||||
LOCAL = 1
|
||||
|
||||
TILECOORD_TO_STRING = {
|
||||
GLOBAL: 'GLOBAL',
|
||||
LOCAL: 'LOCAL',
|
||||
}
|
||||
|
||||
STRING_TO_TILECOORD = {
|
||||
'GLOBAL': GLOBAL,
|
||||
'LOCAL': LOCAL,
|
||||
}
|
||||
|
||||
ADJACENT = 0
|
||||
RANDOM = 1
|
||||
|
||||
PATTERN_TO_STRING = {
|
||||
ADJACENT: 'ADJACENT',
|
||||
RANDOM: 'RANDOM',
|
||||
}
|
||||
|
||||
STRING_TO_PATTERN = {
|
||||
'ADJACENT': ADJACENT,
|
||||
'RANDOM': RANDOM,
|
||||
}
|
||||
|
||||
PARENT = 0
|
||||
WORLD = 1
|
||||
SELF = 2
|
||||
|
||||
SEALEVEL_TO_STRING = {
|
||||
PARENT: 'PARENT',
|
||||
WORLD: 'WORLD',
|
||||
SELF: 'SELF',
|
||||
}
|
||||
|
||||
STRING_TO_SEALEVEL = {
|
||||
'PARENT': PARENT,
|
||||
'WORLD': WORLD,
|
||||
'SELF': SELF,
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
GOAL_TYPE_NONE = 0
|
||||
GOAL_TYPE_POINTS_ORDERED = 1
|
||||
GOAL_TYPE_POINTS_ORDEREDREV = 2
|
||||
GOAL_TYPE_POINTS_RANDOM = 3
|
||||
GOAL_TYPE_POINTS_TREENEAR = 4
|
||||
GOAL_TYPE_POINTS_TREEFAR = 5
|
||||
GOAL_TYPE_POINTS_WORLD_CITIES = 6
|
||||
|
||||
GOAL_TYPE_TO_STRING = {
|
||||
GOAL_TYPE_NONE: 'NONE',
|
||||
GOAL_TYPE_POINTS_ORDERED: 'POINTS_ORDERED',
|
||||
GOAL_TYPE_POINTS_ORDEREDREV: 'POINTS_ORDEREDREV',
|
||||
GOAL_TYPE_POINTS_RANDOM: 'POINTS_RANDOM',
|
||||
GOAL_TYPE_POINTS_TREENEAR: 'POINTS_TREENEAR',
|
||||
GOAL_TYPE_POINTS_TREEFAR: 'POINTS_TREEFAR',
|
||||
GOAL_TYPE_POINTS_WORLD_CITIES: 'POINTS_WORLD_CITIES',
|
||||
}
|
||||
|
||||
STRING_TO_GOAL_TYPE = {
|
||||
'NONE': GOAL_TYPE_NONE,
|
||||
'POINTS_ORDERED': GOAL_TYPE_POINTS_ORDERED,
|
||||
'POINTS_ORDEREDREV': GOAL_TYPE_POINTS_ORDEREDREV,
|
||||
'POINTS_RANDOM': GOAL_TYPE_POINTS_RANDOM,
|
||||
'POINTS_TREENEAR': GOAL_TYPE_POINTS_TREENEAR,
|
||||
'POINTS_TREEFAR': GOAL_TYPE_POINTS_TREEFAR,
|
||||
'POINTS_WORLD_CITIES': GOAL_TYPE_POINTS_WORLD_CITIES,
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,116 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
import struct
|
||||
import zlib
|
||||
|
||||
|
||||
def read_dword(cache_file):
|
||||
data = cache_file.read(4)
|
||||
return struct.unpack('<I', data)[0]
|
||||
|
||||
|
||||
def read_qword(cache_file):
|
||||
dwords = struct.unpack('<II', cache_file.read(8))
|
||||
buffer = struct.pack('<II', dwords[1], dwords[0])
|
||||
return struct.unpack('<Q', buffer)[0]
|
||||
|
||||
|
||||
def read_resource_data(cache_file, start, length):
|
||||
current_position = cache_file.tell()
|
||||
|
||||
cache_file.seek(start)
|
||||
data = cache_file.read(length)
|
||||
|
||||
cache_file.seek(current_position)
|
||||
return data
|
||||
|
||||
|
||||
def load_cache_file(filename):
|
||||
cache_file = open(filename, 'rb')
|
||||
num_resources = read_dword(cache_file)
|
||||
read_dword(cache_file)
|
||||
read_dword(cache_file)
|
||||
read_dword(cache_file)
|
||||
|
||||
resources = []
|
||||
for _ in range(num_resources):
|
||||
resource_id = read_qword(cache_file)
|
||||
resource_offset = read_dword(cache_file)
|
||||
resource_decompressed_len = read_dword(cache_file)
|
||||
resource_compressed_len = read_dword(cache_file)
|
||||
|
||||
resource_data = read_resource_data(
|
||||
cache_file,
|
||||
resource_offset,
|
||||
resource_compressed_len
|
||||
)
|
||||
|
||||
if resource_decompressed_len > resource_compressed_len:
|
||||
resource_data = zlib.decompress(resource_data)
|
||||
|
||||
resources.append([
|
||||
resource_id,
|
||||
resource_data
|
||||
])
|
||||
|
||||
return resources
|
||||
|
||||
|
||||
def write_dword(cache_file, value):
|
||||
data = struct.pack('<I', value)
|
||||
cache_file.write(data)
|
||||
|
||||
|
||||
def write_qword(cache_file, value):
|
||||
qword = struct.pack('<Q', value)
|
||||
dwords = [
|
||||
struct.unpack('<I', qword[:4])[0],
|
||||
struct.unpack('<I', qword[4:])[0],
|
||||
]
|
||||
data = struct.pack('<II', dwords[1], dwords[0])
|
||||
cache_file.write(data)
|
||||
|
||||
|
||||
def write_bytes(cache_file, value):
|
||||
cache_file.write(value)
|
||||
|
||||
|
||||
def save_cache_file(filename, resources, compress=True):
|
||||
cache_file = open(filename, 'wb')
|
||||
|
||||
num_resources = len(resources)
|
||||
|
||||
last_offset = 0
|
||||
last_offset += 0x10 # header
|
||||
last_offset += num_resources * 0x14 # resource_headers
|
||||
|
||||
data_start = last_offset
|
||||
for resource in resources:
|
||||
resource.append(last_offset)
|
||||
resource.append(len(resource[1]))
|
||||
|
||||
if compress:
|
||||
resource[1] = zlib.compress(resource[1])
|
||||
resource.append(len(resource[1]))
|
||||
|
||||
last_offset += resource[4]
|
||||
|
||||
data_end = last_offset
|
||||
write_dword(cache_file, num_resources)
|
||||
write_dword(cache_file, data_start)
|
||||
write_dword(cache_file, data_end)
|
||||
write_dword(cache_file, 0xffffffff)
|
||||
for resource in resources:
|
||||
write_qword(cache_file, resource[0])
|
||||
write_dword(cache_file, resource[2])
|
||||
write_dword(cache_file, resource[3])
|
||||
write_dword(cache_file, resource[4])
|
||||
|
||||
for resource in resources:
|
||||
write_bytes(cache_file, resource[1])
|
||||
@@ -0,0 +1,108 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
import struct
|
||||
from io import BytesIO
|
||||
|
||||
|
||||
class ResStream:
|
||||
def __init__(self, initial_bytes=b''):
|
||||
self.buffer = BytesIO(initial_bytes)
|
||||
|
||||
def read_byte(self):
|
||||
data = self.buffer.read(1)
|
||||
return struct.unpack('<B', data)[0]
|
||||
|
||||
def read_bytes(self, n):
|
||||
data = self.buffer.read(n)
|
||||
return data
|
||||
|
||||
def read_word(self):
|
||||
data = self.buffer.read(2)
|
||||
return struct.unpack('<H', data)[0]
|
||||
|
||||
def read_dword(self):
|
||||
data = self.buffer.read(4)
|
||||
return struct.unpack('<I', data)[0]
|
||||
|
||||
def read_qword(self):
|
||||
dwords = struct.unpack('<II', self.buffer.read(8))
|
||||
buffer = struct.pack('<II', dwords[1], dwords[0])
|
||||
return struct.unpack('<Q', buffer)[0]
|
||||
|
||||
def read_float(self):
|
||||
data = self.buffer.read(4)
|
||||
return struct.unpack('<f', data)[0]
|
||||
|
||||
def read_tuple(self):
|
||||
data = self.buffer.read(12)
|
||||
return struct.unpack('<fff', data)
|
||||
|
||||
def read_bool(self):
|
||||
data = self.buffer.read(1)
|
||||
return True if struct.unpack('<B', data)[0] else False
|
||||
|
||||
def read_wchar(self):
|
||||
data = self.buffer.read(2)
|
||||
return chr(struct.unpack('<H', data)[0])
|
||||
|
||||
def read_string(self):
|
||||
length = self.read_dword()
|
||||
data = [self.read_wchar() for _ in range(length)]
|
||||
return ''.join(data)
|
||||
|
||||
def write_byte(self, value):
|
||||
data = struct.pack('<B', value)
|
||||
self.buffer.write(data)
|
||||
|
||||
def write_bytes(self, value):
|
||||
data = value
|
||||
self.buffer.write(data)
|
||||
|
||||
def write_word(self, value):
|
||||
data = struct.pack('<H', value)
|
||||
self.buffer.write(data)
|
||||
|
||||
def write_dword(self, value):
|
||||
data = struct.pack('<I', value)
|
||||
self.buffer.write(data)
|
||||
|
||||
def write_qword(self, value):
|
||||
qword = struct.pack('<Q', value)
|
||||
dwords = [
|
||||
struct.unpack('<I', qword[:4])[0],
|
||||
struct.unpack('<I', qword[4:])[0],
|
||||
]
|
||||
data = struct.pack('<II', dwords[1], dwords[0])
|
||||
self.buffer.write(data)
|
||||
|
||||
def write_float(self, value):
|
||||
data = struct.pack('<f', value)
|
||||
self.buffer.write(data)
|
||||
|
||||
def write_tuple(self, value):
|
||||
data = struct.pack('<fff', *value)
|
||||
self.buffer.write(data)
|
||||
|
||||
def write_bool(self, value):
|
||||
data = struct.pack('<B', 1 if value else 0)
|
||||
self.buffer.write(data)
|
||||
|
||||
def write_wchar(self, value):
|
||||
data = struct.pack('<H', value)
|
||||
self.buffer.write(data)
|
||||
|
||||
def write_string(self, value):
|
||||
length = len(value)
|
||||
self.write_dword(length)
|
||||
for char in value.encode('utf-16-le'):
|
||||
self.write_byte(char)
|
||||
|
||||
def get_bytes(self):
|
||||
self.buffer.seek(0)
|
||||
return self.buffer.read()
|
||||
@@ -0,0 +1,10 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from .ArcFileCache import load_cache_file, save_cache_file
|
||||
from .ResStream import ResStream
|
||||
@@ -0,0 +1,47 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
def _hash_string_short(array):
|
||||
v04 = (8 * array[7]) & 0xffffffff
|
||||
v05 = v04 ^ array[4]
|
||||
v06 = (16 * v05) & 0xffffffff
|
||||
v07 = array[5] ^ v06
|
||||
v08 = (16 * v07) & 0xffffffff
|
||||
v09 = array[6] ^ v08
|
||||
v10 = (32 * v09) & 0xffffffff
|
||||
v11 = array[2] ^ v10
|
||||
v12 = (32 * v11) & 0xffffffff
|
||||
v13 = (array[1] ^ v12)
|
||||
v14 = (32 * v13) & 0xffffffff
|
||||
v15 = (array[7] ^ 0x5A0) >> 2
|
||||
return array[0] ^ (v15) ^ (v14)
|
||||
|
||||
|
||||
def _hash_string_long(array):
|
||||
i = 0
|
||||
result = 0
|
||||
for c in array:
|
||||
v = c - 32
|
||||
result ^= (v << (i)) & 0xffffffff
|
||||
if i > 0x18:
|
||||
result ^= v >> (32 - i)
|
||||
if i >= 0x1b:
|
||||
i -= 32
|
||||
i += 5
|
||||
return result & 0xffffffff
|
||||
|
||||
|
||||
def hash_string(string):
|
||||
array = bytearray(string.encode())
|
||||
length = len(string)
|
||||
|
||||
if (length == 7 or length == 8) and string[3] == '-':
|
||||
array += bytearray(b'\x00')
|
||||
return _hash_string_short(array)
|
||||
else:
|
||||
return _hash_string_long(array)
|
||||
@@ -0,0 +1,19 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
#
|
||||
|
||||
def int32(x):
|
||||
if x > 0xFFFFFFFF:
|
||||
raise OverflowError
|
||||
if x > 0x7FFFFFFF:
|
||||
x = int(0x100000000 - x)
|
||||
if x < 2147483648:
|
||||
return -x
|
||||
else:
|
||||
return -2147483648
|
||||
return x
|
||||
@@ -0,0 +1,39 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.util import ResStream
|
||||
|
||||
|
||||
class ArcDungeonInfo:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.dungeon_template_id = stream.read_qword()
|
||||
self.dungeon_unknown = stream.read_qword()
|
||||
self.dungeon_spawn_location = stream.read_tuple()
|
||||
self.dungeon_y_offset = stream.read_float()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_qword(self.dungeon_template_id)
|
||||
stream.write_qword(self.dungeon_unknown)
|
||||
stream.write_tuple(self.dungeon_spawn_location)
|
||||
stream.write_float(self.dungeon_y_offset)
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['dungeon_template_id'] = self.dungeon_template_id
|
||||
data['dungeon_unknown'] = self.dungeon_unknown
|
||||
data['dungeon_spawn_location'] = self.dungeon_spawn_location
|
||||
data['dungeon_y_offset'] = self.dungeon_y_offset
|
||||
return data
|
||||
|
||||
def load_json(self, data):
|
||||
self.dungeon_template_id = data['dungeon_template_id']
|
||||
self.dungeon_unknown = data['dungeon_unknown']
|
||||
self.dungeon_spawn_location = data['dungeon_spawn_location']
|
||||
self.dungeon_y_offset = data['dungeon_y_offset']
|
||||
@@ -0,0 +1,79 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.enums.zone.arc_mobile import *
|
||||
from arcane.util import ResStream
|
||||
from .mobile.HirelingInfo import HirelingInfo
|
||||
from .mobile.MerchantInfo import MerchantInfo
|
||||
from .mobile.MinionInfo import MinionInfo
|
||||
from .mobile.MobileInfo import MobileInfo
|
||||
from .mobile.ShopKeeperInfo import ShopKeeperInfo
|
||||
from .mobile.TrainerInfo import TrainerInfo
|
||||
|
||||
|
||||
class ArcMobile:
|
||||
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.mobile_type = stream.read_dword()
|
||||
|
||||
if self.mobile_type == 1:
|
||||
self.mobile_data = MobileInfo()
|
||||
self.mobile_data.load_binary(stream)
|
||||
elif self.mobile_type == 2:
|
||||
self.mobile_data = MobileInfo()
|
||||
self.mobile_data.load_binary(stream)
|
||||
elif self.mobile_type == 3:
|
||||
self.mobile_data = ShopKeeperInfo()
|
||||
self.mobile_data.load_binary(stream)
|
||||
elif self.mobile_type == 4:
|
||||
self.mobile_data = TrainerInfo()
|
||||
self.mobile_data.load_binary(stream)
|
||||
elif self.mobile_type == 8:
|
||||
self.mobile_data = MerchantInfo()
|
||||
self.mobile_data.load_binary(stream)
|
||||
elif self.mobile_type == 9:
|
||||
self.mobile_data = HirelingInfo()
|
||||
self.mobile_data.load_binary(stream)
|
||||
elif self.mobile_type == 10:
|
||||
self.mobile_data = HirelingInfo()
|
||||
self.mobile_data.load_binary(stream)
|
||||
elif self.mobile_type == 11:
|
||||
self.mobile_data = MinionInfo()
|
||||
self.mobile_data.load_binary(stream)
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.mobile_type)
|
||||
self.mobile_data.save_binary(stream)
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['mobile_type'] = MOBILE_TO_STRING[self.mobile_type]
|
||||
data['mobile_data'] = self.mobile_data.save_json()
|
||||
return data
|
||||
|
||||
def load_json(self, data):
|
||||
self.mobile_type = STRING_TO_MOBILE[data['mobile_type']]
|
||||
if self.mobile_type == 1:
|
||||
self.mobile_data = MobileInfo()
|
||||
elif self.mobile_type == 2:
|
||||
self.mobile_data = MobileInfo()
|
||||
elif self.mobile_type == 3:
|
||||
self.mobile_data = ShopKeeperInfo()
|
||||
elif self.mobile_type == 4:
|
||||
self.mobile_data = TrainerInfo()
|
||||
elif self.mobile_type == 8:
|
||||
self.mobile_data = MerchantInfo()
|
||||
elif self.mobile_type == 9:
|
||||
self.mobile_data = HirelingInfo()
|
||||
elif self.mobile_type == 10:
|
||||
self.mobile_data = HirelingInfo()
|
||||
elif self.mobile_type == 11:
|
||||
self.mobile_data = MinionInfo()
|
||||
self.mobile_data.load_json(data['mobile_data'])
|
||||
@@ -0,0 +1,270 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# 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.enums.zone.arc_prop import *
|
||||
from arcane.objects.common.Inventory import Inventory
|
||||
from arcane.util import ResStream
|
||||
from .ArcMobile import ArcMobile
|
||||
from .mobile.ArcBasicZoneObjectInfo import ArcBasicZoneObjectInfo
|
||||
|
||||
|
||||
class ArcPropInfo:
|
||||
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.prop_basic_zone = ArcBasicZoneObjectInfo()
|
||||
self.prop_basic_zone.load_binary(stream)
|
||||
self.prop_has_platform = stream.read_bool()
|
||||
self.prop_platform_height = stream.read_float()
|
||||
self.prop_is_light_data = stream.read_bool()
|
||||
if self.prop_is_light_data:
|
||||
self.prop_light_color = [stream.read_dword() for _ in range(4)]
|
||||
self.prop_light_radius = stream.read_float()
|
||||
self.prop_light_flicker = stream.read_dword()
|
||||
self.prop_light_cube_map = stream.read_dword()
|
||||
num_content_props = stream.read_dword()
|
||||
self.prop_content_props = [ArcProp() for _ in range(num_content_props)]
|
||||
for prop in self.prop_content_props:
|
||||
prop.load_binary(stream)
|
||||
num_content_mobiles = stream.read_dword()
|
||||
self.prop_content_mobiles = [ArcMobile() for _ in range(num_content_mobiles)]
|
||||
for mobile in self.prop_content_mobiles:
|
||||
mobile.load_binary(stream)
|
||||
num_descriptors = stream.read_dword()
|
||||
self.prop_descriptors = [stream.read_string() for _ in range(num_descriptors)]
|
||||
self.prop_registry = stream.read_dword()
|
||||
if self.prop_registry:
|
||||
self.prop_registry_name = stream.read_string()
|
||||
self.prop_has_zone_event = stream.read_bool()
|
||||
self.prop_has_teleporter = stream.read_bool()
|
||||
|
||||
if self.prop_has_zone_event:
|
||||
self.prop_zone_event = stream.read_dword()
|
||||
|
||||
if self.prop_has_teleporter:
|
||||
self.prop_teleporter = stream.read_dword()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
self.prop_basic_zone.save_binary(stream)
|
||||
stream.write_bool(self.prop_has_platform)
|
||||
stream.write_float(self.prop_platform_height)
|
||||
stream.write_bool(self.prop_is_light_data)
|
||||
if self.prop_is_light_data:
|
||||
for i in range(4):
|
||||
stream.write_dword(self.prop_light_color[i])
|
||||
stream.write_float(self.prop_light_radius)
|
||||
stream.write_dword(self.prop_light_flicker)
|
||||
stream.write_dword(self.prop_light_cube_map)
|
||||
|
||||
stream.write_dword(len(self.prop_content_props))
|
||||
for prop in self.prop_content_props:
|
||||
prop.save_binary(stream)
|
||||
|
||||
stream.write_dword(len(self.prop_content_mobiles))
|
||||
for mobile in self.prop_content_mobiles:
|
||||
mobile.save_binary(stream)
|
||||
|
||||
stream.write_dword(len(self.prop_descriptors))
|
||||
for descriptor in self.prop_descriptors:
|
||||
stream.write_string(descriptor)
|
||||
|
||||
stream.write_dword(self.prop_registry)
|
||||
if self.prop_registry:
|
||||
stream.write_string(self.prop_registry_name)
|
||||
|
||||
stream.write_bool(self.prop_has_zone_event)
|
||||
stream.write_bool(self.prop_has_teleporter)
|
||||
|
||||
if self.prop_has_zone_event:
|
||||
stream.write_dword(self.prop_zone_event)
|
||||
if self.prop_has_teleporter:
|
||||
stream.write_dword(self.prop_teleporter)
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['prop_basic_zone'] = self.prop_basic_zone.save_json()
|
||||
data['prop_has_platform'] = self.prop_has_platform
|
||||
data['prop_platform_height'] = self.prop_platform_height
|
||||
data['prop_is_light_data'] = self.prop_is_light_data
|
||||
if self.prop_is_light_data:
|
||||
data['prop_light_color'] = self.prop_light_color
|
||||
data['prop_light_radius'] = self.prop_light_radius
|
||||
data['prop_light_flicker'] = self.prop_light_flicker
|
||||
data['prop_light_cube_map'] = self.prop_light_cube_map
|
||||
data['prop_content_props'] = []
|
||||
for prop in self.prop_content_props:
|
||||
data['prop_content_props'].append(prop.save_json())
|
||||
data['prop_content_mobiles'] = []
|
||||
for mobile in self.prop_content_mobiles:
|
||||
data['prop_content_mobiles'].append(mobile.save_json())
|
||||
data['prop_descriptors'] = self.prop_descriptors
|
||||
data['prop_registry'] = self.prop_registry
|
||||
if self.prop_registry:
|
||||
data['prop_registry_name'] = self.prop_registry_name
|
||||
data['prop_has_zone_event'] = self.prop_has_zone_event
|
||||
data['prop_has_teleporter'] = self.prop_has_teleporter
|
||||
if self.prop_has_zone_event:
|
||||
data['prop_zone_event'] = hash_to_string(self.prop_zone_event)
|
||||
if self.prop_has_teleporter:
|
||||
data['prop_teleporter'] = hash_to_string(self.prop_teleporter)
|
||||
return data
|
||||
|
||||
def load_json(self, data):
|
||||
self.prop_basic_zone = ArcBasicZoneObjectInfo()
|
||||
self.prop_basic_zone.load_json(data['prop_basic_zone'])
|
||||
self.prop_has_platform = data['prop_has_platform']
|
||||
self.prop_platform_height = data['prop_platform_height']
|
||||
self.prop_is_light_data = data['prop_is_light_data']
|
||||
if self.prop_is_light_data:
|
||||
self.prop_light_color = data['prop_light_color']
|
||||
self.prop_light_radius = data['prop_light_radius']
|
||||
self.prop_light_flicker = data['prop_light_flicker']
|
||||
self.prop_light_cube_map = data['prop_light_cube_map']
|
||||
self.prop_content_props = []
|
||||
for prop_data in data['prop_content_props']:
|
||||
prop = ArcProp()
|
||||
prop.load_json(prop_data)
|
||||
self.prop_content_props.append(prop)
|
||||
self.prop_content_mobiles = []
|
||||
for mobile_data in data['prop_content_mobiles']:
|
||||
mobile = ArcMobile()
|
||||
mobile.load_json(mobile_data)
|
||||
self.prop_content_mobiles.append(mobile)
|
||||
self.prop_descriptors = data['prop_descriptors']
|
||||
self.prop_registry = data['prop_registry']
|
||||
if self.prop_registry:
|
||||
self.prop_registry_name = data['prop_registry_name']
|
||||
self.prop_has_zone_event = data['prop_has_zone_event']
|
||||
self.prop_has_teleporter = data['prop_has_teleporter']
|
||||
if self.prop_has_zone_event:
|
||||
self.prop_zone_event = string_to_hash(data['prop_zone_event'])
|
||||
if self.prop_has_teleporter:
|
||||
self.prop_teleporter = string_to_hash(data['prop_teleporter'])
|
||||
|
||||
|
||||
class ArcCityPropInfo(ArcPropInfo):
|
||||
def load_binary(self, stream: ResStream):
|
||||
super().load_binary(stream)
|
||||
self.city_prop_gm_guild = stream.read_dword()
|
||||
self.city_prop_gm_nation = stream.read_dword()
|
||||
self.city_prop_asset_rank = stream.read_dword()
|
||||
self.city_prop_asset_funds = stream.read_dword()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
super().save_binary(stream)
|
||||
stream.write_dword(self.city_prop_gm_guild)
|
||||
stream.write_dword(self.city_prop_gm_nation)
|
||||
stream.write_dword(self.city_prop_asset_rank)
|
||||
stream.write_dword(self.city_prop_asset_funds)
|
||||
|
||||
def save_json(self):
|
||||
data = super().save_json()
|
||||
data['city_prop_gm_guild'] = self.city_prop_gm_guild
|
||||
data['city_prop_gm_nation'] = self.city_prop_gm_nation
|
||||
data['city_prop_asset_rank'] = self.city_prop_asset_rank
|
||||
data['city_prop_asset_funds'] = self.city_prop_asset_funds
|
||||
return data
|
||||
|
||||
def load_json(self, data):
|
||||
super().load_json(data)
|
||||
self.city_prop_gm_guild = data['city_prop_gm_guild']
|
||||
self.city_prop_gm_nation = data['city_prop_gm_nation']
|
||||
self.city_prop_asset_rank = data['city_prop_asset_rank']
|
||||
self.city_prop_asset_funds = data['city_prop_asset_funds']
|
||||
|
||||
|
||||
class ArcContainerInfo(ArcPropInfo):
|
||||
def load_binary(self, stream: ResStream):
|
||||
super().load_binary(stream)
|
||||
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_trapped_rank = stream.read_dword()
|
||||
num_booties = stream.read_dword()
|
||||
self.container_booties = [Inventory() for _ in range(num_booties)]
|
||||
for inventory in self.container_booties:
|
||||
inventory.load_binary(stream)
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
super().save_binary(stream)
|
||||
stream.write_dword(self.container_locked)
|
||||
stream.write_dword(self.container_locked_rank)
|
||||
stream.write_dword(self.container_barred)
|
||||
stream.write_dword(self.container_barred_rank)
|
||||
stream.write_dword(self.container_trapped)
|
||||
stream.write_dword(self.container_trapped_rank)
|
||||
stream.write_dword(len(self.container_booties))
|
||||
for inventory in self.container_booties:
|
||||
inventory.save_binary(stream)
|
||||
|
||||
def save_json(self):
|
||||
data = super().save_json()
|
||||
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_trapped_rank'] = self.container_trapped_rank
|
||||
data['container_booties'] = []
|
||||
for inventory in self.container_booties:
|
||||
data['container_booties'].append(inventory.save_json())
|
||||
return data
|
||||
|
||||
def load_json(self, data):
|
||||
super().load_json(data)
|
||||
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_trapped_rank = data['container_trapped_rank']
|
||||
self.container_booties = []
|
||||
for inventory_data in data['container_booties']:
|
||||
inventory = Inventory()
|
||||
inventory.load_json(inventory_data)
|
||||
self.container_booties.append(inventory)
|
||||
|
||||
|
||||
class ArcProp:
|
||||
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.prop_type = stream.read_dword()
|
||||
|
||||
if self.prop_type == 5:
|
||||
self.prop_data = ArcPropInfo()
|
||||
self.prop_data.load_binary(stream)
|
||||
elif self.prop_type == 6:
|
||||
self.prop_data = ArcCityPropInfo()
|
||||
self.prop_data.load_binary(stream)
|
||||
elif self.prop_type == 7:
|
||||
self.prop_data = ArcContainerInfo()
|
||||
self.prop_data.load_binary(stream)
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.prop_type)
|
||||
self.prop_data.save_binary(stream)
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['prop_type'] = PROP_TO_STRING[self.prop_type]
|
||||
data['prop_data'] = self.prop_data.save_json()
|
||||
return data
|
||||
|
||||
def load_json(self, data):
|
||||
self.prop_type = STRING_TO_PROP[data['prop_type']]
|
||||
if self.prop_type == 5:
|
||||
self.prop_data = ArcPropInfo()
|
||||
elif self.prop_type == 6:
|
||||
self.prop_data = ArcCityPropInfo()
|
||||
elif self.prop_type == 7:
|
||||
self.prop_data = ArcContainerInfo()
|
||||
self.prop_data.load_json(data['prop_data'])
|
||||
@@ -0,0 +1,44 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.util import ResStream
|
||||
|
||||
|
||||
class ArcSoundInfo:
|
||||
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.sound_playlist = stream.read_string()
|
||||
self.sound_id = stream.read_dword()
|
||||
self.sound_template = stream.read_string()
|
||||
self.sound_location = stream.read_tuple()
|
||||
self.sound_radius = stream.read_float()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_string(self.sound_playlist)
|
||||
stream.write_dword(self.sound_id)
|
||||
stream.write_string(self.sound_template)
|
||||
stream.write_tuple(self.sound_location)
|
||||
stream.write_float(self.sound_radius)
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['sound_playlist'] = self.sound_playlist
|
||||
data['sound_id'] = self.sound_id
|
||||
data['sound_template'] = self.sound_template
|
||||
data['sound_location'] = self.sound_location
|
||||
data['sound_radius'] = self.sound_radius
|
||||
return data
|
||||
|
||||
def load_json(self, data):
|
||||
self.sound_playlist = data['sound_playlist']
|
||||
self.sound_id = data['sound_id']
|
||||
self.sound_template = data['sound_template']
|
||||
self.sound_location = data['sound_location']
|
||||
self.sound_radius = data['sound_radius']
|
||||
@@ -0,0 +1,141 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.enums.zone.arc_terraingen import *
|
||||
from arcane.util import ResStream
|
||||
|
||||
|
||||
class ArcTerrainGen:
|
||||
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.terrain_type = stream.read_dword()
|
||||
if self.terrain_type in [1, 2, 3, 5]:
|
||||
self.terrain_max_x = stream.read_float()
|
||||
self.terrain_max_z = stream.read_float()
|
||||
self.terrain_h = stream.read_float()
|
||||
self.terrain_lacunarity = stream.read_float()
|
||||
self.terrain_octaves = stream.read_dword()
|
||||
self.terrain_offset = stream.read_float()
|
||||
self.terrain_gain = stream.read_float()
|
||||
self.terrain_seeds = [
|
||||
stream.read_dword(),
|
||||
stream.read_dword(),
|
||||
]
|
||||
if self.terrain_type == 4:
|
||||
self.terrain_max_x = stream.read_float()
|
||||
self.terrain_max_z = stream.read_float()
|
||||
self.terrain_height = stream.read_float()
|
||||
if self.terrain_type == 6:
|
||||
self.terrain_max_x = stream.read_float()
|
||||
self.terrain_max_z = stream.read_float()
|
||||
self.terrain_x_size = stream.read_float()
|
||||
self.terrain_z_size = stream.read_float()
|
||||
self.terrain_mesh = stream.read_qword()
|
||||
if self.terrain_type == 7:
|
||||
self.terrain_max_x = stream.read_float()
|
||||
self.terrain_max_z = stream.read_float()
|
||||
self.terrain_x_size = stream.read_float()
|
||||
self.terrain_z_size = stream.read_float()
|
||||
self.terrain_min_y = stream.read_float()
|
||||
self.terrain_max_y = stream.read_float()
|
||||
self.terrain_image = stream.read_qword()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.terrain_type)
|
||||
if self.terrain_type in [1, 2, 3, 5]:
|
||||
stream.write_float(self.terrain_max_x)
|
||||
stream.write_float(self.terrain_max_z)
|
||||
stream.write_float(self.terrain_h)
|
||||
stream.write_float(self.terrain_lacunarity)
|
||||
stream.write_dword(self.terrain_octaves)
|
||||
stream.write_float(self.terrain_offset)
|
||||
stream.write_float(self.terrain_gain)
|
||||
stream.read_dword(self.terrain_seeds[0])
|
||||
stream.read_dword(self.terrain_seeds[1])
|
||||
if self.terrain_type == 4:
|
||||
stream.write_float(self.terrain_max_x)
|
||||
stream.write_float(self.terrain_max_z)
|
||||
stream.write_float(self.terrain_height)
|
||||
if self.terrain_type == 6:
|
||||
stream.write_float(self.terrain_max_x)
|
||||
stream.write_float(self.terrain_max_z)
|
||||
stream.write_float(self.terrain_x_size)
|
||||
stream.write_float(self.terrain_z_size)
|
||||
stream.write_qword(self.terrain_mesh)
|
||||
if self.terrain_type == 7:
|
||||
stream.write_float(self.terrain_max_x)
|
||||
stream.write_float(self.terrain_max_z)
|
||||
stream.write_float(self.terrain_x_size)
|
||||
stream.write_float(self.terrain_z_size)
|
||||
stream.write_float(self.terrain_min_y)
|
||||
stream.write_float(self.terrain_max_y)
|
||||
stream.write_qword(self.terrain_image)
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['terrain_type'] = TERRAIN_TYPE_TO_STRING[self.terrain_type]
|
||||
if self.terrain_type in [1, 2, 3, 5]:
|
||||
data['terrain_max_x'] = self.terrain_max_x
|
||||
data['terrain_max_z'] = self.terrain_max_z
|
||||
data['terrain_h'] = self.terrain_h
|
||||
data['terrain_lacunarity'] = self.terrain_lacunarity
|
||||
data['terrain_octaves'] = self.terrain_octaves
|
||||
data['terrain_offset'] = self.terrain_offset
|
||||
data['terrain_gain'] = self.terrain_gain
|
||||
data['terrain_seeds'] = self.terrain_seeds
|
||||
if self.terrain_type == 4:
|
||||
data['terrain_max_x'] = self.terrain_max_x
|
||||
data['terrain_max_z'] = self.terrain_max_z
|
||||
data['terrain_height'] = self.terrain_height
|
||||
if self.terrain_type == 6:
|
||||
data['terrain_max_x'] = self.terrain_max_x
|
||||
data['terrain_max_z'] = self.terrain_max_z
|
||||
data['terrain_x_size'] = self.terrain_x_size
|
||||
data['terrain_z_size'] = self.terrain_z_size
|
||||
data['terrain_mesh'] = self.terrain_mesh
|
||||
if self.terrain_type == 7:
|
||||
data['terrain_max_x'] = self.terrain_max_x
|
||||
data['terrain_max_z'] = self.terrain_max_z
|
||||
data['terrain_x_size'] = self.terrain_x_size
|
||||
data['terrain_z_size'] = self.terrain_z_size
|
||||
data['terrain_min_y'] = self.terrain_min_y
|
||||
data['terrain_max_y'] = self.terrain_max_y
|
||||
data['terrain_image'] = self.terrain_image
|
||||
return data
|
||||
|
||||
def load_json(self, data):
|
||||
self.terrain_type = STRING_TO_TERRAIN_TYPE[data['terrain_type']]
|
||||
if self.terrain_type in [1, 2, 3, 5]:
|
||||
self.terrain_max_x = data['terrain_max_x']
|
||||
self.terrain_max_z = data['terrain_max_z']
|
||||
self.terrain_h = data['terrain_h']
|
||||
self.terrain_lacunarity = data['terrain_lacunarity']
|
||||
self.terrain_octaves = data['terrain_octaves']
|
||||
self.terrain_offset = data['terrain_offset']
|
||||
self.terrain_gain = data['terrain_gain']
|
||||
self.terrain_seeds = data['terrain_seeds']
|
||||
if self.terrain_type == 4:
|
||||
self.terrain_max_x = data['terrain_max_x']
|
||||
self.terrain_max_z = data['terrain_max_z']
|
||||
self.terrain_height = data['terrain_height']
|
||||
if self.terrain_type == 6:
|
||||
self.terrain_max_x = data['terrain_max_x']
|
||||
self.terrain_max_z = data['terrain_max_z']
|
||||
self.terrain_x_size = data['terrain_x_size']
|
||||
self.terrain_z_size = data['terrain_z_size']
|
||||
self.terrain_mesh = data['terrain_mesh']
|
||||
if self.terrain_type == 7:
|
||||
self.terrain_max_x = data['terrain_max_x']
|
||||
self.terrain_max_z = data['terrain_max_z']
|
||||
self.terrain_x_size = data['terrain_x_size']
|
||||
self.terrain_z_size = data['terrain_z_size']
|
||||
self.terrain_min_y = data['terrain_min_y']
|
||||
self.terrain_max_y = data['terrain_max_y']
|
||||
self.terrain_image = data['terrain_image']
|
||||
@@ -0,0 +1,408 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.enums.zone.arc_zone import *
|
||||
from arcane.util import ResStream
|
||||
from .ArcDungeonInfo import ArcDungeonInfo
|
||||
from .ArcMobile import ArcMobile
|
||||
from .ArcProp import ArcProp
|
||||
from .ArcSoundInfo import ArcSoundInfo
|
||||
from .ArcTerrainGen import ArcTerrainGen
|
||||
from .ArcZoneBiomState import ArcZoneBiomState
|
||||
from .ArcZoneEvent import ArcZoneEvent
|
||||
from .ArcZoneGoal import ArcZoneGoal
|
||||
from .TerrainObjectInfo import TerrainObjectInfo
|
||||
from .WaterInfo import WaterInfo
|
||||
from .WeatherEventInfo import WeatherEventInfo
|
||||
|
||||
|
||||
class ArcZone:
|
||||
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.zone_type = stream.read_dword()
|
||||
self.zone_name = stream.read_string()
|
||||
self.zone_custom_texture = stream.read_qword()
|
||||
self.zone_width_threshold = stream.read_dword()
|
||||
self.zone_material_threshold = stream.read_dword()
|
||||
self.zone_max_width_index = stream.read_dword()
|
||||
self.zone_max_material_index = stream.read_dword()
|
||||
self.zone_custom_texture_wrap = stream.read_bool()
|
||||
self.zone_peace_zone = stream.read_bool()
|
||||
self.zone_guild_zone = stream.read_bool()
|
||||
self.zone_minor_radius = stream.read_float()
|
||||
self.zone_major_radius = stream.read_float()
|
||||
self.zone_min_blend = stream.read_float()
|
||||
self.zone_max_blend = stream.read_float()
|
||||
self.zone_influence = stream.read_float()
|
||||
self.zone_unknown1 = stream.read_float()
|
||||
self.zone_y_offset = stream.read_float()
|
||||
self.zone_global_height = stream.read_float()
|
||||
self.zone_transition_height = stream.read_float()
|
||||
self.zone_upper_transition_height = stream.read_float()
|
||||
self.zone_tile_cord_type = stream.read_dword()
|
||||
self.zone_tile_pattern_prob = stream.read_float()
|
||||
self.zone_pattern_type = stream.read_dword()
|
||||
self.zone_sea_level_index = stream.read_dword()
|
||||
self.zone_sea_level = stream.read_float()
|
||||
self.zone_sea_level_type = stream.read_dword()
|
||||
self.zone_grad = stream.read_float()
|
||||
self.zone_tile_set = stream.read_qword()
|
||||
self.zone_song = stream.read_qword()
|
||||
self.zone_is_biom = stream.read_bool()
|
||||
if self.zone_is_biom:
|
||||
self.zone_biom = ArcZoneBiomState()
|
||||
self.zone_biom.load_binary(stream)
|
||||
num_weather_events = stream.read_dword()
|
||||
self.zone_weather_events = [WeatherEventInfo() for _ in range(num_weather_events)]
|
||||
for event in self.zone_weather_events:
|
||||
event.load_binary(stream)
|
||||
self.zone_has_water = stream.read_bool()
|
||||
if self.zone_has_water:
|
||||
self.zone_water = WaterInfo()
|
||||
self.zone_water.load_binary(stream)
|
||||
self.zone_has_terrain_gen = stream.read_bool()
|
||||
if self.zone_has_terrain_gen:
|
||||
self.zone_terrain_gen = ArcTerrainGen()
|
||||
self.zone_terrain_gen.load_binary(stream)
|
||||
num_patterns = stream.read_dword()
|
||||
self.zone_patterns = [
|
||||
[
|
||||
stream.read_dword(),
|
||||
stream.read_float(),
|
||||
] for _ in range(num_patterns)
|
||||
]
|
||||
num_alts = stream.read_dword()
|
||||
self.zone_alts = [stream.read_float() for _ in range(num_alts)]
|
||||
num_terrain_objects = stream.read_dword()
|
||||
self.zone_terrain_objects = [TerrainObjectInfo() for _ in range(num_terrain_objects)]
|
||||
for obj in self.zone_terrain_objects:
|
||||
obj.load_binary(stream)
|
||||
num_mobiles = stream.read_dword()
|
||||
self.zone_mobile_info = [ArcMobile() for _ in range(num_mobiles)]
|
||||
for mobile in self.zone_mobile_info:
|
||||
mobile.load_binary(stream)
|
||||
num_sounds = stream.read_dword()
|
||||
self.zone_sound_info = [ArcSoundInfo() for _ in range(num_sounds)]
|
||||
for sound in self.zone_sound_info:
|
||||
sound.load_binary(stream)
|
||||
num_dungeons = stream.read_dword()
|
||||
self.zone_dungeon_info = [ArcDungeonInfo() for _ in range(num_dungeons)]
|
||||
for dungeon in self.zone_dungeon_info:
|
||||
dungeon.load_binary(stream)
|
||||
num_props = stream.read_dword()
|
||||
self.zone_prop_info = [ArcProp() for _ in range(num_props)]
|
||||
for prop in self.zone_prop_info:
|
||||
prop.load_binary(stream)
|
||||
num_architectures = stream.read_dword()
|
||||
self.zone_architecture = [stream.read_string() for _ in range(num_architectures)]
|
||||
num_events = stream.read_dword()
|
||||
self.zone_events = [ArcZoneEvent() for _ in range(num_events)]
|
||||
for event in self.zone_events:
|
||||
event.load_binary(stream)
|
||||
num_point_sets = stream.read_dword()
|
||||
self.zone_point_sets = [ArcZoneGoal() for _ in range(num_point_sets)]
|
||||
for point_set in self.zone_point_sets:
|
||||
point_set.load_binary(stream)
|
||||
self.zone_has_layers = stream.read_bool()
|
||||
if self.zone_has_layers:
|
||||
self.zone_base_texture = stream.read_qword()
|
||||
num_layer_texture_ids = stream.read_dword()
|
||||
self.zone_layer_texture_ids = [stream.read_qword() for _ in range(num_layer_texture_ids)]
|
||||
num_layer_mappings = stream.read_dword()
|
||||
self.zone_layer_mappings = []
|
||||
for _ in range(num_layer_mappings):
|
||||
layer = stream.read_qword()
|
||||
num = stream.read_dword()
|
||||
textures = [stream.read_qword() for _ in range(num)]
|
||||
self.zone_layer_mappings.append([layer, textures])
|
||||
else:
|
||||
num_textures = stream.read_dword()
|
||||
self.zone_textures = [
|
||||
[
|
||||
stream.read_qword(),
|
||||
stream.read_float(),
|
||||
stream.read_float(),
|
||||
stream.read_float(),
|
||||
stream.read_float(),
|
||||
stream.read_float(),
|
||||
stream.read_dword(),
|
||||
stream.read_dword(),
|
||||
stream.read_dword(),
|
||||
] for _ in range(num_textures)
|
||||
]
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.zone_type)
|
||||
stream.write_string(self.zone_name)
|
||||
stream.write_qword(self.zone_custom_texture)
|
||||
stream.write_dword(self.zone_width_threshold)
|
||||
stream.write_dword(self.zone_material_threshold)
|
||||
stream.write_dword(self.zone_max_width_index)
|
||||
stream.write_dword(self.zone_max_material_index)
|
||||
stream.write_bool(self.zone_custom_texture_wrap)
|
||||
stream.write_bool(self.zone_peace_zone)
|
||||
stream.write_bool(self.zone_guild_zone)
|
||||
stream.write_float(self.zone_minor_radius)
|
||||
stream.write_float(self.zone_major_radius)
|
||||
stream.write_float(self.zone_min_blend)
|
||||
stream.write_float(self.zone_max_blend)
|
||||
stream.write_float(self.zone_influence)
|
||||
stream.write_float(self.zone_unknown1)
|
||||
stream.write_float(self.zone_y_offset)
|
||||
stream.write_float(self.zone_global_height)
|
||||
stream.write_float(self.zone_transition_height)
|
||||
stream.write_float(self.zone_upper_transition_height)
|
||||
stream.write_dword(self.zone_tile_cord_type)
|
||||
stream.write_float(self.zone_tile_pattern_prob)
|
||||
stream.write_dword(self.zone_pattern_type)
|
||||
stream.write_dword(self.zone_sea_level_index)
|
||||
stream.write_float(self.zone_sea_level)
|
||||
stream.write_dword(self.zone_sea_level_type)
|
||||
stream.write_float(self.zone_grad)
|
||||
stream.write_qword(self.zone_tile_set)
|
||||
stream.write_qword(self.zone_song)
|
||||
stream.write_bool(self.zone_is_biom)
|
||||
if self.zone_is_biom:
|
||||
self.zone_biom.save_binary(stream)
|
||||
stream.write_dword(len(self.zone_weather_events))
|
||||
for event in self.zone_weather_events:
|
||||
event.save_binary(stream)
|
||||
stream.write_bool(self.zone_has_water)
|
||||
if self.zone_has_water:
|
||||
self.zone_water.save_binary(stream)
|
||||
stream.write_bool(self.zone_has_terrain_gen)
|
||||
if self.zone_has_terrain_gen:
|
||||
self.zone_terrain_gen.save_binary(stream)
|
||||
stream.write_dword(len(self.zone_patterns))
|
||||
for pattern in self.zone_patterns:
|
||||
stream.write_dword(pattern[0])
|
||||
stream.write_float(pattern[1])
|
||||
stream.write_dword(len(self.zone_alts))
|
||||
for alt in self.zone_alts:
|
||||
stream.write_float(alt)
|
||||
stream.write_dword(len(self.zone_terrain_objects))
|
||||
for obj in self.zone_terrain_objects:
|
||||
obj.save_binary(stream)
|
||||
stream.write_dword(len(self.zone_mobile_info))
|
||||
for mobile in self.zone_mobile_info:
|
||||
mobile.save_binary(stream)
|
||||
stream.write_dword(len(self.zone_sound_info))
|
||||
for sound in self.zone_sound_info:
|
||||
sound.save_binary(stream)
|
||||
stream.write_dword(len(self.zone_dungeon_info))
|
||||
for dungeon in self.zone_dungeon_info:
|
||||
dungeon.save_binary(stream)
|
||||
stream.write_dword(len(self.zone_prop_info))
|
||||
for prop in self.zone_prop_info:
|
||||
prop.save_binary(stream)
|
||||
stream.write_dword(len(self.zone_architecture))
|
||||
for arch in self.zone_architecture:
|
||||
stream.write_string(arch)
|
||||
stream.write_dword(len(self.zone_events))
|
||||
for event in self.zone_events:
|
||||
event.save_binary(stream)
|
||||
stream.write_dword(len(self.zone_point_sets))
|
||||
for point_set in self.zone_point_sets:
|
||||
point_set.save_binary(stream)
|
||||
|
||||
stream.write_bool(self.zone_has_layers)
|
||||
if self.zone_has_layers:
|
||||
stream.write_qword(self.zone_base_texture)
|
||||
stream.write_dword(len(self.zone_layer_texture_ids))
|
||||
for texture_id in self.zone_layer_texture_ids:
|
||||
stream.write_qword(texture_id)
|
||||
|
||||
stream.write_dword(len(self.zone_layer_mappings))
|
||||
for layer, textures in self.zone_layer_mappings:
|
||||
stream.write_qword(layer)
|
||||
stream.write_dword(len(textures))
|
||||
for texture in textures:
|
||||
stream.write_qword(texture)
|
||||
else:
|
||||
stream.write_dword(len(self.zone_textures))
|
||||
for texture in self.zone_textures:
|
||||
stream.write_qword(texture[0])
|
||||
stream.write_float(texture[1])
|
||||
stream.write_float(texture[2])
|
||||
stream.write_float(texture[3])
|
||||
stream.write_float(texture[4])
|
||||
stream.write_float(texture[5])
|
||||
stream.write_dword(texture[6])
|
||||
stream.write_dword(texture[7])
|
||||
stream.write_dword(texture[8])
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['zone_type'] = ZONE_TO_STRING[self.zone_type]
|
||||
data['zone_name'] = self.zone_name
|
||||
data['zone_custom_texture'] = self.zone_custom_texture
|
||||
data['zone_width_threshold'] = self.zone_width_threshold
|
||||
data['zone_material_threshold'] = self.zone_material_threshold
|
||||
data['zone_max_width_index'] = self.zone_max_width_index
|
||||
data['zone_max_material_index'] = self.zone_max_material_index
|
||||
data['zone_custom_texture_wrap'] = self.zone_custom_texture_wrap
|
||||
data['zone_peace_zone'] = self.zone_peace_zone
|
||||
data['zone_guild_zone'] = self.zone_guild_zone
|
||||
data['zone_minor_radius'] = self.zone_minor_radius
|
||||
data['zone_major_radius'] = self.zone_major_radius
|
||||
data['zone_min_blend'] = self.zone_min_blend
|
||||
data['zone_max_blend'] = self.zone_max_blend
|
||||
data['zone_influence'] = self.zone_influence
|
||||
data['zone_unknown1'] = self.zone_unknown1
|
||||
data['zone_y_offset'] = self.zone_y_offset
|
||||
data['zone_global_height'] = self.zone_global_height
|
||||
data['zone_transition_height'] = self.zone_transition_height
|
||||
data['zone_upper_transition_height'] = self.zone_upper_transition_height
|
||||
data['zone_tile_cord_type'] = TILECOORD_TO_STRING[self.zone_tile_cord_type]
|
||||
data['zone_tile_pattern_prob'] = self.zone_tile_pattern_prob
|
||||
data['zone_pattern_type'] = PATTERN_TO_STRING[self.zone_pattern_type]
|
||||
data['zone_sea_level_index'] = self.zone_sea_level_index
|
||||
data['zone_sea_level'] = self.zone_sea_level
|
||||
data['zone_sea_level_type'] = SEALEVEL_TO_STRING[self.zone_sea_level_type]
|
||||
data['zone_grad'] = self.zone_grad
|
||||
data['zone_tile_set'] = self.zone_tile_set
|
||||
data['zone_song'] = self.zone_song
|
||||
data['zone_is_biom'] = self.zone_is_biom
|
||||
if self.zone_is_biom:
|
||||
data['zone_biom'] = self.zone_biom.save_json()
|
||||
data['zone_weather_events'] = []
|
||||
for event in self.zone_weather_events:
|
||||
data['zone_weather_events'].append(event.save_json())
|
||||
data['zone_has_water'] = self.zone_has_water
|
||||
if self.zone_has_water:
|
||||
data['zone_water'] = self.zone_water.save_json()
|
||||
data['zone_has_terrain_gen'] = self.zone_has_terrain_gen
|
||||
if self.zone_has_terrain_gen:
|
||||
data['zone_terrain_gen'] = self.zone_terrain_gen.save_json()
|
||||
data['zone_patterns'] = self.zone_patterns
|
||||
data['zone_alts'] = self.zone_alts
|
||||
data['zone_terrain_objects'] = []
|
||||
for obj in self.zone_terrain_objects:
|
||||
data['zone_terrain_objects'].append(obj.save_json())
|
||||
data['zone_mobile_info'] = []
|
||||
for mobile in self.zone_mobile_info:
|
||||
data['zone_mobile_info'].append(mobile.save_json())
|
||||
data['zone_sound_info'] = []
|
||||
for sound in self.zone_sound_info:
|
||||
data['zone_sound_info'].append(sound.save_json())
|
||||
data['zone_dungeon_info'] = []
|
||||
for dungeon in self.zone_dungeon_info:
|
||||
data['zone_dungeon_info'].append(dungeon.save_json())
|
||||
data['zone_prop_info'] = []
|
||||
for prop in self.zone_prop_info:
|
||||
data['zone_prop_info'].append(prop.save_json())
|
||||
data['zone_architecture'] = self.zone_architecture
|
||||
data['zone_events'] = []
|
||||
for event in self.zone_events:
|
||||
data['zone_events'].append(event.save_json())
|
||||
data['zone_point_sets'] = []
|
||||
for point_set in self.zone_point_sets:
|
||||
data['zone_point_sets'].append(point_set.save_json())
|
||||
data['zone_has_layers'] = self.zone_has_layers
|
||||
if self.zone_has_layers:
|
||||
data['zone_base_texture'] = self.zone_base_texture
|
||||
data['zone_layer_texture_ids'] = self.zone_layer_texture_ids
|
||||
data['zone_layer_mappings'] = self.zone_layer_mappings
|
||||
else:
|
||||
data['zone_textures'] = self.zone_textures
|
||||
return data
|
||||
|
||||
def load_json(self, data):
|
||||
self.zone_type = STRING_TO_ZONE[data['zone_type']]
|
||||
self.zone_name = data['zone_name']
|
||||
self.zone_custom_texture = data['zone_custom_texture']
|
||||
self.zone_width_threshold = data['zone_width_threshold']
|
||||
self.zone_material_threshold = data['zone_material_threshold']
|
||||
self.zone_max_width_index = data['zone_max_width_index']
|
||||
self.zone_max_material_index = data['zone_max_material_index']
|
||||
self.zone_custom_texture_wrap = data['zone_custom_texture_wrap']
|
||||
self.zone_peace_zone = data['zone_peace_zone']
|
||||
self.zone_guild_zone = data['zone_guild_zone']
|
||||
self.zone_minor_radius = data['zone_minor_radius']
|
||||
self.zone_major_radius = data['zone_major_radius']
|
||||
self.zone_min_blend = data['zone_min_blend']
|
||||
self.zone_max_blend = data['zone_max_blend']
|
||||
self.zone_influence = data['zone_influence']
|
||||
self.zone_unknown1 = data['zone_unknown1']
|
||||
self.zone_y_offset = data['zone_y_offset']
|
||||
self.zone_global_height = data['zone_global_height']
|
||||
self.zone_transition_height = data['zone_transition_height']
|
||||
self.zone_upper_transition_height = data['zone_upper_transition_height']
|
||||
self.zone_tile_cord_type = STRING_TO_TILECOORD[data['zone_tile_cord_type']]
|
||||
self.zone_tile_pattern_prob = data['zone_tile_pattern_prob']
|
||||
self.zone_pattern_type = STRING_TO_PATTERN[data['zone_pattern_type']]
|
||||
self.zone_sea_level_index = data['zone_sea_level_index']
|
||||
self.zone_sea_level = data['zone_sea_level']
|
||||
self.zone_sea_level_type = STRING_TO_SEALEVEL[data['zone_sea_level_type']]
|
||||
self.zone_grad = data['zone_grad']
|
||||
self.zone_tile_set = data['zone_tile_set']
|
||||
self.zone_song = data['zone_song']
|
||||
self.zone_is_biom = data['zone_is_biom']
|
||||
if self.zone_is_biom:
|
||||
self.zone_biom = ArcZoneBiomState()
|
||||
self.zone_biom.load_json(data['zone_biom'])
|
||||
self.zone_weather_events = []
|
||||
for event_data in data['zone_weather_events']:
|
||||
event = WeatherEventInfo()
|
||||
event.load_json(event_data)
|
||||
self.zone_weather_events.append(event)
|
||||
self.zone_has_water = data['zone_has_water']
|
||||
if self.zone_has_water:
|
||||
self.zone_water = WaterInfo()
|
||||
self.zone_water.load_json(data['zone_water'])
|
||||
self.zone_has_terrain_gen = data['zone_has_terrain_gen']
|
||||
if self.zone_has_terrain_gen:
|
||||
self.zone_terrain_gen = ArcTerrainGen()
|
||||
self.zone_terrain_gen.load_json(data['zone_terrain_gen'])
|
||||
self.zone_patterns = data['zone_patterns']
|
||||
self.zone_alts = data['zone_alts']
|
||||
self.zone_terrain_objects = []
|
||||
for obj_data in data['zone_terrain_objects']:
|
||||
obj = TerrainObjectInfo()
|
||||
obj.load_json(obj_data)
|
||||
self.zone_terrain_objects.append(obj)
|
||||
self.zone_mobile_info = []
|
||||
for mobile_data in data['zone_mobile_info']:
|
||||
mobile = ArcMobile()
|
||||
mobile.load_json(mobile_data)
|
||||
self.zone_mobile_info.append(mobile)
|
||||
self.zone_sound_info = []
|
||||
for sound_data in data['zone_sound_info']:
|
||||
sound = ArcSoundInfo()
|
||||
sound.load_json(sound_data)
|
||||
self.zone_sound_info.append(sound)
|
||||
self.zone_dungeon_info = []
|
||||
for dungeon_data in data['zone_dungeon_info']:
|
||||
dungeon = ArcDungeonInfo()
|
||||
dungeon.load_json(dungeon_data)
|
||||
self.zone_dungeon_info.append(dungeon)
|
||||
self.zone_prop_info = []
|
||||
for prop_data in data['zone_prop_info']:
|
||||
prop = ArcProp()
|
||||
prop.load_json(prop_data)
|
||||
self.zone_prop_info.append(prop)
|
||||
self.zone_architecture = data['zone_architecture']
|
||||
self.zone_events = []
|
||||
for event_data in data['zone_events']:
|
||||
event = ArcZoneEvent()
|
||||
event.load_json(event_data)
|
||||
self.zone_events.append(event)
|
||||
self.zone_point_sets = []
|
||||
for point_set_data in data['zone_point_sets']:
|
||||
point_set = ArcZoneGoal()
|
||||
point_set.load_json(point_set_data)
|
||||
self.zone_point_sets.append(point_set)
|
||||
self.zone_has_layers = data['zone_has_layers']
|
||||
if self.zone_has_layers:
|
||||
self.zone_base_texture = data['zone_base_texture']
|
||||
self.zone_layer_texture_ids = data['zone_layer_texture_ids']
|
||||
self.zone_layer_mappings = data['zone_layer_mappings']
|
||||
else:
|
||||
self.zone_textures = data['zone_textures']
|
||||
@@ -0,0 +1,37 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# 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 ArcZoneBiomState:
|
||||
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.biom_sky_state_id = stream.read_dword()
|
||||
self.biom_environment_state_id = stream.read_dword()
|
||||
self.biom_weather_state_id = stream.read_dword()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.biom_sky_state_id)
|
||||
stream.write_dword(self.biom_environment_state_id)
|
||||
stream.write_dword(self.biom_weather_state_id)
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['biom_sky_state_id'] = hash_to_string(self.biom_sky_state_id)
|
||||
data['biom_environment_state_id'] = hash_to_string(self.biom_environment_state_id)
|
||||
data['biom_weather_state_id'] = hash_to_string(self.biom_weather_state_id)
|
||||
return data
|
||||
|
||||
def load_json(self, data):
|
||||
self.biom_sky_state_id = string_to_hash(data['biom_sky_state_id'])
|
||||
self.biom_environment_state_id = string_to_hash(data['biom_environment_state_id'])
|
||||
self.biom_weather_state_id = string_to_hash(data['biom_weather_state_id'])
|
||||
@@ -0,0 +1,62 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from arcane.util import ResStream
|
||||
|
||||
|
||||
class ArcZTriggerAction:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.zone_trigger_action_type = stream.read_dword()
|
||||
self.zone_trigger_action_unknown1 = stream.read_bool()
|
||||
self.zone_trigger_action_is_timed = stream.read_bool()
|
||||
self.zone_trigger_action_unknown2 = stream.read_bool()
|
||||
|
||||
if self.zone_trigger_action_is_timed:
|
||||
self.zone_trigger_action_time_begin = stream.read_float()
|
||||
self.zone_trigger_action_time_end = stream.read_float()
|
||||
self.zone_trigger_action_has_state = stream.read_bool()
|
||||
if self.zone_trigger_action_has_state:
|
||||
self.zone_trigger_action_new_state = stream.read_dword()
|
||||
num_specifics = stream.read_dword()
|
||||
self.zone_trigger_action_specifics = [stream.read_dword() for _ in range(num_specifics)]
|
||||
num_items = stream.read_dword()
|
||||
self.zone_trigger_action_items = [stream.read_dword() for _ in range(num_items)]
|
||||
num_parent_states = stream.read_dword()
|
||||
self.zone_trigger_action_parent_states = [stream.read_dword() for _ in range(num_parent_states)]
|
||||
|
||||
|
||||
class ArcZoneEventInfo:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.zone_event_recycle = stream.read_dword()
|
||||
self.zone_event_spawn_radius = stream.read_float()
|
||||
self.zone_event_fc_label = stream.read_string()
|
||||
self.zone_event_event_name = stream.read_string()
|
||||
self.zone_event_unknown1 = stream.read_dword()
|
||||
self.zone_event_spawn_location = stream.read_tuple()
|
||||
self.zone_event_parent_name = stream.read_string()
|
||||
self.zone_event_unknown2 = stream.read_dword()
|
||||
self.zone_event_unknown3 = stream.read_bool()
|
||||
num_triggers = stream.read_dword()
|
||||
self.zone_event_triggers = [ArcZTriggerAction() for _ in range(num_triggers)]
|
||||
for action in self.zone_event_triggers:
|
||||
action.load_binary(stream)
|
||||
|
||||
|
||||
class ArcZoneEvent:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.zone_event_type = stream.read_dword()
|
||||
|
||||
if self.zone_event_type == 1:
|
||||
self.zone_event_data = ArcZoneEventInfo()
|
||||
self.zone_event_data.load_binary(stream)
|
||||
elif self.zone_event_type == 2:
|
||||
self.zone_event_data = ArcZoneEventInfo()
|
||||
self.zone_event_data.load_binary(stream)
|
||||
elif self.zone_event_type == 3:
|
||||
self.zone_event_data = ArcZoneEventInfo()
|
||||
self.zone_event_data.load_binary(stream)
|
||||
@@ -0,0 +1,93 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# 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.enums.zone.arc_zone_goal import *
|
||||
from arcane.util import ResStream
|
||||
|
||||
|
||||
class ArcZoneGoalPoint:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.zone_goal_point_vectors = [stream.read_dword() for _ in range(6)]
|
||||
self.zone_goal_point_location = stream.read_tuple()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
for i in range(6):
|
||||
stream.write_dword(self.zone_goal_point_vectors[i])
|
||||
stream.write_tuple(self.zone_goal_point_location)
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['zone_goal_point_vectors'] = self.zone_goal_point_vectors
|
||||
data['zone_goal_point_location'] = self.zone_goal_point_location
|
||||
return data
|
||||
|
||||
def load_json(self, data):
|
||||
self.zone_goal_point_vectors = data['zone_goal_point_vectors']
|
||||
self.zone_goal_point_location = data['zone_goal_point_location']
|
||||
|
||||
|
||||
class ArcZoneGoal:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.zone_goal_type = stream.read_dword()
|
||||
self.zone_goal_value = stream.read_dword()
|
||||
self.zone_goal_name = stream.read_string()
|
||||
self.zone_goal_delay = stream.read_dword()
|
||||
self.zone_goal_has_teleport_registry = stream.read_bool()
|
||||
if self.zone_goal_has_teleport_registry:
|
||||
self.zone_goal_teleport_registry = stream.read_dword()
|
||||
self.zone_goal_dungeon = stream.read_qword()
|
||||
num_points = stream.read_dword()
|
||||
self.zone_goal_points = [ArcZoneGoalPoint() for _ in range(num_points)]
|
||||
for point in self.zone_goal_points:
|
||||
point.load_binary(stream)
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.zone_goal_type)
|
||||
stream.write_dword(self.zone_goal_value)
|
||||
stream.write_string(self.zone_goal_name)
|
||||
stream.write_dword(self.zone_goal_delay)
|
||||
stream.write_bool(self.zone_goal_has_teleport_registry)
|
||||
if self.zone_goal_has_teleport_registry:
|
||||
stream.write_dword(self.zone_goal_teleport_registry)
|
||||
stream.write_qword(self.zone_goal_dungeon)
|
||||
stream.write_dword(len(self.zone_goal_points))
|
||||
for point in self.zone_goal_points:
|
||||
point.save_binary(stream)
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['zone_goal_type'] = GOAL_TYPE_TO_STRING[self.zone_goal_type]
|
||||
data['zone_goal_value'] = hash_to_string(self.zone_goal_value)
|
||||
data['zone_goal_name'] = self.zone_goal_name
|
||||
data['zone_goal_delay'] = self.zone_goal_delay
|
||||
data['zone_goal_has_teleport_registry'] = self.zone_goal_has_teleport_registry
|
||||
if self.zone_goal_has_teleport_registry:
|
||||
data['zone_goal_teleport_registry'] = hash_to_string(self.zone_goal_teleport_registry)
|
||||
data['zone_goal_dungeon'] = self.zone_goal_dungeon
|
||||
data['zone_goal_points'] = []
|
||||
for point in self.zone_goal_points:
|
||||
data['zone_goal_points'].append(point.save_json())
|
||||
return data
|
||||
|
||||
def load_json(self, data):
|
||||
self.zone_goal_type = STRING_TO_GOAL_TYPE[data['zone_goal_type']]
|
||||
self.zone_goal_value = string_to_hash(data['zone_goal_value'])
|
||||
self.zone_goal_name = data['zone_goal_name']
|
||||
self.zone_goal_delay = data['zone_goal_delay']
|
||||
self.zone_goal_has_teleport_registry = data['zone_goal_has_teleport_registry']
|
||||
if self.zone_goal_has_teleport_registry:
|
||||
self.zone_goal_teleport_registry = string_to_hash(data['zone_goal_teleport_registry'])
|
||||
self.zone_goal_dungeon = data['zone_goal_dungeon']
|
||||
self.zone_goal_points = []
|
||||
for point_data in data['zone_goal_points']:
|
||||
point = ArcZoneGoalPoint()
|
||||
point.load_json(point_data)
|
||||
self.zone_goal_points.append(point)
|
||||
@@ -0,0 +1,92 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.util import ResStream
|
||||
|
||||
|
||||
class TerrainObjectInfo:
|
||||
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.terrain_object_id = stream.read_qword()
|
||||
self.terrain_object_h = stream.read_float()
|
||||
self.terrain_object_lacunarity = stream.read_float()
|
||||
self.terrain_object_octaves = stream.read_dword()
|
||||
self.terrain_object_offset = stream.read_float()
|
||||
self.terrain_object_gain = stream.read_float()
|
||||
self.terrain_object_min_alt = stream.read_float()
|
||||
self.terrain_object_max_alt = stream.read_float()
|
||||
self.terrain_object_min_slope = stream.read_float()
|
||||
self.terrain_object_max_slope = stream.read_float()
|
||||
self.terrain_object_max_pop = stream.read_dword()
|
||||
self.terrain_object_is_fractal_pop = stream.read_bool()
|
||||
self.terrain_object_unknown1 = stream.read_dword()
|
||||
self.terrain_object_y_offset = stream.read_float()
|
||||
self.terrain_object_pop_image_id = stream.read_qword()
|
||||
self.terrain_object_image_min_y = stream.read_float()
|
||||
self.terrain_object_image_max_y = stream.read_float()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_qword(self.terrain_object_id)
|
||||
stream.write_float(self.terrain_object_h)
|
||||
stream.write_float(self.terrain_object_lacunarity)
|
||||
stream.write_dword(self.terrain_object_octaves)
|
||||
stream.write_float(self.terrain_object_offset)
|
||||
stream.write_float(self.terrain_object_gain)
|
||||
stream.write_float(self.terrain_object_min_alt)
|
||||
stream.write_float(self.terrain_object_max_alt)
|
||||
stream.write_float(self.terrain_object_min_slope)
|
||||
stream.write_float(self.terrain_object_max_slope)
|
||||
stream.write_dword(self.terrain_object_max_pop)
|
||||
stream.write_bool(self.terrain_object_is_fractal_pop)
|
||||
stream.write_dword(self.terrain_object_unknown1)
|
||||
stream.write_float(self.terrain_object_y_offset)
|
||||
stream.write_qword(self.terrain_object_pop_image_id)
|
||||
stream.write_float(self.terrain_object_image_min_y)
|
||||
stream.write_float(self.terrain_object_image_max_y)
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['terrain_object_id'] = self.terrain_object_id
|
||||
data['terrain_object_h'] = self.terrain_object_h
|
||||
data['terrain_object_lacunarity'] = self.terrain_object_lacunarity
|
||||
data['terrain_object_octaves'] = self.terrain_object_octaves
|
||||
data['terrain_object_offset'] = self.terrain_object_offset
|
||||
data['terrain_object_gain'] = self.terrain_object_gain
|
||||
data['terrain_object_min_alt'] = self.terrain_object_min_alt
|
||||
data['terrain_object_max_alt'] = self.terrain_object_max_alt
|
||||
data['terrain_object_min_slope'] = self.terrain_object_min_slope
|
||||
data['terrain_object_max_slope'] = self.terrain_object_max_slope
|
||||
data['terrain_object_max_pop'] = self.terrain_object_max_pop
|
||||
data['terrain_object_is_fractal_pop'] = self.terrain_object_is_fractal_pop
|
||||
data['terrain_object_unknown1'] = self.terrain_object_unknown1
|
||||
data['terrain_object_y_offset'] = self.terrain_object_y_offset
|
||||
data['terrain_object_pop_image_id'] = self.terrain_object_pop_image_id
|
||||
data['terrain_object_image_min_y'] = self.terrain_object_image_min_y
|
||||
data['terrain_object_image_max_y'] = self.terrain_object_image_max_y
|
||||
return data
|
||||
|
||||
def load_json(self, data):
|
||||
self.terrain_object_id = data['terrain_object_id']
|
||||
self.terrain_object_h = data['terrain_object_h']
|
||||
self.terrain_object_lacunarity = data['terrain_object_lacunarity']
|
||||
self.terrain_object_octaves = data['terrain_object_octaves']
|
||||
self.terrain_object_offset = data['terrain_object_offset']
|
||||
self.terrain_object_gain = data['terrain_object_gain']
|
||||
self.terrain_object_min_alt = data['terrain_object_min_alt']
|
||||
self.terrain_object_max_alt = data['terrain_object_max_alt']
|
||||
self.terrain_object_min_slope = data['terrain_object_min_slope']
|
||||
self.terrain_object_max_slope = data['terrain_object_max_slope']
|
||||
self.terrain_object_max_pop = data['terrain_object_max_pop']
|
||||
self.terrain_object_is_fractal_pop = data['terrain_object_is_fractal_pop']
|
||||
self.terrain_object_unknown1 = data['terrain_object_unknown1']
|
||||
self.terrain_object_y_offset = data['terrain_object_y_offset']
|
||||
self.terrain_object_pop_image_id = data['terrain_object_pop_image_id']
|
||||
self.terrain_object_image_min_y = data['terrain_object_image_min_y']
|
||||
self.terrain_object_image_max_y = data['terrain_object_image_max_y']
|
||||
@@ -0,0 +1,92 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.util import ResStream
|
||||
|
||||
|
||||
class WaterInfo:
|
||||
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.water_texture = stream.read_qword()
|
||||
self.water_unknown1 = [
|
||||
stream.read_float(),
|
||||
stream.read_float(),
|
||||
stream.read_float(),
|
||||
stream.read_float(),
|
||||
]
|
||||
self.water_x_wave_length = stream.read_float()
|
||||
self.water_z_wave_length = stream.read_float()
|
||||
self.water_x_speed = stream.read_float()
|
||||
self.water_z_speed = stream.read_float()
|
||||
self.water_unknown2 = stream.read_float()
|
||||
self.water_amplitude = stream.read_float()
|
||||
self.water_vertex_density = stream.read_float()
|
||||
self.water_texture_density = stream.read_float()
|
||||
self.water_color = [
|
||||
stream.read_float(),
|
||||
stream.read_float(),
|
||||
stream.read_float(),
|
||||
stream.read_float(),
|
||||
]
|
||||
self.water_reflectivity = stream.read_float()
|
||||
self.water_eye_factor = stream.read_float()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_qword(self.water_texture)
|
||||
stream.write_float(self.water_unknown1[0])
|
||||
stream.write_float(self.water_unknown1[1])
|
||||
stream.write_float(self.water_unknown1[2])
|
||||
stream.write_float(self.water_unknown1[3])
|
||||
stream.write_float(self.water_x_wave_length)
|
||||
stream.write_float(self.water_z_wave_length)
|
||||
stream.write_float(self.water_x_speed)
|
||||
stream.write_float(self.water_z_speed)
|
||||
stream.write_float(self.water_unknown2)
|
||||
stream.write_float(self.water_amplitude)
|
||||
stream.write_float(self.water_vertex_density)
|
||||
stream.write_float(self.water_texture_density)
|
||||
stream.write_float(self.water_color[0])
|
||||
stream.write_float(self.water_color[1])
|
||||
stream.write_float(self.water_color[2])
|
||||
stream.write_float(self.water_color[3])
|
||||
stream.write_float(self.water_reflectivity)
|
||||
stream.write_float(self.water_eye_factor)
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['water_texture'] = self.water_texture
|
||||
data['water_unknown1'] = self.water_unknown1
|
||||
data['water_x_wave_length'] = self.water_x_wave_length
|
||||
data['water_z_wave_length'] = self.water_z_wave_length
|
||||
data['water_x_speed'] = self.water_x_speed
|
||||
data['water_z_speed'] = self.water_z_speed
|
||||
data['water_unknown2'] = self.water_unknown2
|
||||
data['water_amplitude'] = self.water_amplitude
|
||||
data['water_vertex_density'] = self.water_vertex_density
|
||||
data['water_texture_density'] = self.water_texture_density
|
||||
data['water_color'] = self.water_color
|
||||
data['water_reflectivity'] = self.water_reflectivity
|
||||
data['water_eye_factor'] = self.water_eye_factor
|
||||
return data
|
||||
|
||||
def load_json(self, data):
|
||||
self.water_texture = data['water_texture']
|
||||
self.water_unknown1 = data['water_unknown1']
|
||||
self.water_x_wave_length = data['water_x_wave_length']
|
||||
self.water_z_wave_length = data['water_z_wave_length']
|
||||
self.water_x_speed = data['water_x_speed']
|
||||
self.water_z_speed = data['water_z_speed']
|
||||
self.water_unknown2 = data['water_unknown2']
|
||||
self.water_amplitude = data['water_amplitude']
|
||||
self.water_vertex_density = data['water_vertex_density']
|
||||
self.water_texture_density = data['water_texture_density']
|
||||
self.water_color = data['water_color']
|
||||
self.water_reflectivity = data['water_reflectivity']
|
||||
self.water_eye_factor = data['water_eye_factor']
|
||||
@@ -0,0 +1,52 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# 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 WeatherEventInfo:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.weather_event_effect_id = stream.read_dword()
|
||||
self.weather_event_spawn_location = stream.read_tuple()
|
||||
self.weather_event_min_duration = stream.read_float()
|
||||
self.weather_event_duration_variant = stream.read_float()
|
||||
self.weather_event_time_to_respawn = stream.read_float()
|
||||
self.weather_event_init_height_off_ground = stream.read_float()
|
||||
self.weather_event_local_top = stream.read_bool()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_dword(self.weather_event_effect_id)
|
||||
stream.write_tuple(self.weather_event_spawn_location)
|
||||
stream.write_float(self.weather_event_min_duration)
|
||||
stream.write_float(self.weather_event_duration_variant)
|
||||
stream.write_float(self.weather_event_time_to_respawn)
|
||||
stream.write_float(self.weather_event_init_height_off_ground)
|
||||
stream.write_bool(self.weather_event_local_top)
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['weather_event_effect_id'] = hash_to_string(self.weather_event_effect_id)
|
||||
data['weather_event_spawn_location'] = self.weather_event_spawn_location
|
||||
data['weather_event_min_duration'] = self.weather_event_min_duration
|
||||
data['weather_event_duration_variant'] = self.weather_event_duration_variant
|
||||
data['weather_event_time_to_respawn'] = self.weather_event_time_to_respawn
|
||||
data['weather_event_init_height_off_ground'] = self.weather_event_init_height_off_ground
|
||||
data['weather_event_local_top'] = self.weather_event_local_top
|
||||
return data
|
||||
|
||||
def load_json(self, data):
|
||||
self.weather_event_effect_id = string_to_hash(data['weather_event_effect_id'])
|
||||
self.weather_event_spawn_location = data['weather_event_spawn_location']
|
||||
self.weather_event_min_duration = data['weather_event_min_duration']
|
||||
self.weather_event_duration_variant = data['weather_event_duration_variant']
|
||||
self.weather_event_time_to_respawn = data['weather_event_time_to_respawn']
|
||||
self.weather_event_init_height_off_ground = data['weather_event_init_height_off_ground']
|
||||
self.weather_event_local_top = data['weather_event_local_top']
|
||||
@@ -0,0 +1,9 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from .ArcZone import ArcZone
|
||||
@@ -0,0 +1,83 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.objects.common.SparseData import SparseData
|
||||
from arcane.util import ResStream
|
||||
|
||||
|
||||
class ArcBasicZoneObjectInfo:
|
||||
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.basic_zone_spawn_location = stream.read_tuple()
|
||||
self.basic_zone_name_override = stream.read_string()
|
||||
self.basic_zone_time_to_respawn = stream.read_float()
|
||||
self.basic_zone_spawn_radius = stream.read_float()
|
||||
self.basic_zone_y_rot = stream.read_float()
|
||||
self.basic_zone_template_id = stream.read_qword()
|
||||
self.basic_zone_unknown1 = stream.read_qword()
|
||||
self.basic_zone_level_number = stream.read_dword()
|
||||
self.basic_zone_room_number = stream.read_dword()
|
||||
self.basic_zone_unknown2 = stream.read_qword()
|
||||
self.basic_zone_dungeon_level = stream.read_dword()
|
||||
self.basic_zone_dungeon_row = stream.read_dword()
|
||||
self.basic_zone_dungeon_column = stream.read_dword()
|
||||
self.basic_zone_sparse_data = SparseData()
|
||||
self.basic_zone_sparse_data.load_binary(stream)
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
stream.write_tuple(self.basic_zone_spawn_location)
|
||||
stream.write_string(self.basic_zone_name_override)
|
||||
stream.write_float(self.basic_zone_time_to_respawn)
|
||||
stream.write_float(self.basic_zone_spawn_radius)
|
||||
stream.write_float(self.basic_zone_y_rot)
|
||||
stream.write_qword(self.basic_zone_template_id)
|
||||
stream.write_qword(self.basic_zone_unknown1)
|
||||
stream.write_dword(self.basic_zone_level_number)
|
||||
stream.write_dword(self.basic_zone_room_number)
|
||||
stream.write_qword(self.basic_zone_unknown2)
|
||||
stream.write_dword(self.basic_zone_dungeon_level)
|
||||
stream.write_dword(self.basic_zone_dungeon_row)
|
||||
stream.write_dword(self.basic_zone_dungeon_column)
|
||||
self.basic_zone_sparse_data.save_binary(stream)
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['basic_zone_spawn_location'] = self.basic_zone_spawn_location
|
||||
data['basic_zone_name_override'] = self.basic_zone_name_override
|
||||
data['basic_zone_time_to_respawn'] = self.basic_zone_time_to_respawn
|
||||
data['basic_zone_spawn_radius'] = self.basic_zone_spawn_radius
|
||||
data['basic_zone_y_rot'] = self.basic_zone_y_rot
|
||||
data['basic_zone_template_id'] = self.basic_zone_template_id
|
||||
data['basic_zone_unknown1'] = self.basic_zone_unknown1
|
||||
data['basic_zone_level_number'] = self.basic_zone_level_number
|
||||
data['basic_zone_room_number'] = self.basic_zone_room_number
|
||||
data['basic_zone_unknown2'] = self.basic_zone_unknown2
|
||||
data['basic_zone_dungeon_level'] = self.basic_zone_dungeon_level
|
||||
data['basic_zone_dungeon_row'] = self.basic_zone_dungeon_row
|
||||
data['basic_zone_dungeon_column'] = self.basic_zone_dungeon_column
|
||||
data['basic_zone_sparse_data'] = self.basic_zone_sparse_data.save_json()
|
||||
return data
|
||||
|
||||
def load_json(self, data):
|
||||
self.basic_zone_spawn_location = data['basic_zone_spawn_location']
|
||||
self.basic_zone_name_override = data['basic_zone_name_override']
|
||||
self.basic_zone_time_to_respawn = data['basic_zone_time_to_respawn']
|
||||
self.basic_zone_spawn_radius = data['basic_zone_spawn_radius']
|
||||
self.basic_zone_y_rot = data['basic_zone_y_rot']
|
||||
self.basic_zone_template_id = data['basic_zone_template_id']
|
||||
self.basic_zone_unknown1 = data['basic_zone_unknown1']
|
||||
self.basic_zone_level_number = data['basic_zone_level_number']
|
||||
self.basic_zone_room_number = data['basic_zone_room_number']
|
||||
self.basic_zone_unknown2 = data['basic_zone_unknown2']
|
||||
self.basic_zone_dungeon_level = data['basic_zone_dungeon_level']
|
||||
self.basic_zone_dungeon_row = data['basic_zone_dungeon_row']
|
||||
self.basic_zone_dungeon_column = data['basic_zone_dungeon_column']
|
||||
self.basic_zone_sparse_data = SparseData()
|
||||
self.basic_zone_sparse_data.load_json(data['basic_zone_sparse_data'])
|
||||
@@ -0,0 +1,129 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from arcane.util import ResStream
|
||||
from .MerchantInfo import MerchantInfo
|
||||
|
||||
|
||||
class Product:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.product_cost = stream.read_dword()
|
||||
self.product_base_time = stream.read_dword()
|
||||
self.product_min_rank = stream.read_dword()
|
||||
self.product_is_complete = stream.read_bool()
|
||||
self.product_is_pending = stream.read_bool()
|
||||
self.product_order_num = stream.read_dword()
|
||||
self.product_time_mod = stream.read_dword()
|
||||
self.product_enchantment = stream.read_dword()
|
||||
self.product_action_prefix_id = stream.read_dword()
|
||||
self.product_action_suffix_id = stream.read_dword()
|
||||
self.product_u = stream.read_dword()
|
||||
self.product_u = stream.read_bool()
|
||||
self.product_id = stream.read_qword()
|
||||
self.product_pending_id = stream.read_qword()
|
||||
self.product_item_type_id = stream.read_qword()
|
||||
self.product_next_complete = [stream.read_dword() for _ in range(6)]
|
||||
|
||||
|
||||
class MinionElement:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.minion_element_id = stream.read_qword()
|
||||
self.minion_element_type = stream.read_qword()
|
||||
self.minion_element_lookup = stream.read_qword()
|
||||
self.minion_element_base_time = stream.read_dword()
|
||||
self.minion_element_mod_time = stream.read_dword()
|
||||
self.minion_element_u = stream.read_dword()
|
||||
self.minion_element_is_complete = stream.read_bool()
|
||||
self.minion_element_next_complete = [stream.read_dword() for _ in range(6)]
|
||||
self.minion_element_name = stream.read_string()
|
||||
self.minion_element_u = stream.read_string()
|
||||
self.minion_element_rank = stream.read_dword()
|
||||
self.minion_element_category = stream.read_dword()
|
||||
self.minion_element_u = stream.read_string()
|
||||
self.minion_element_u = stream.read_string()
|
||||
|
||||
|
||||
class ServiceElement:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.service_element_id = stream.read_qword()
|
||||
self.service_element_keyword = stream.read_dword()
|
||||
self.service_element_key_value = stream.read_dword()
|
||||
self.service_element_description = stream.read_string()
|
||||
self.service_element_unit_description = stream.read_string()
|
||||
self.service_element_cost = stream.read_dword()
|
||||
self.service_element_unit_value = stream.read_dword()
|
||||
self.service_element_min_rank = stream.read_dword()
|
||||
|
||||
|
||||
class HirelingMod:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.hireling_mod_type = stream.read_dword()
|
||||
self.hireling_mod_rank = stream.read_dword()
|
||||
self.hireling_mod_quantity = stream.read_dword()
|
||||
self.hireling_mod_percent = stream.read_float()
|
||||
|
||||
|
||||
class JunkerBasics:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.junker_auto_junk = stream.read_bool()
|
||||
self.junker_auto_junk_magic = stream.read_bool()
|
||||
self.junker_auto_junk_int = stream.read_dword()
|
||||
self.junker_auto_junk_magic_int = stream.read_dword()
|
||||
|
||||
|
||||
class HirelingInfo(MerchantInfo):
|
||||
def load_binary(self, stream: ResStream):
|
||||
super().load_binary(stream)
|
||||
self.hireling_all_items = stream.read_bool()
|
||||
self.hireling_rank = stream.read_dword()
|
||||
self.hireling_title = stream.read_string()
|
||||
self.hireling_salary = stream.read_dword()
|
||||
self.hireling_upgrade_cost = stream.read_dword()
|
||||
self.hireling_upgrade_time = stream.read_dword()
|
||||
self.hireling_can_upgrade = stream.read_bool()
|
||||
self.hireling_use_specified_location = stream.read_bool()
|
||||
self.hireling_category = stream.read_dword()
|
||||
num_npc_features = stream.read_dword()
|
||||
self.hireling_npc_features = [stream.read_dword() for _ in range(num_npc_features)]
|
||||
num_item_types = stream.read_dword()
|
||||
self.hireling_item_types = [stream.read_dword() for _ in range(num_item_types)]
|
||||
num_products = stream.read_dword()
|
||||
self.hireling_products = [Product() for _ in range(num_products)]
|
||||
num_stocks = stream.read_dword()
|
||||
self.hireling_stocks = [Product() for _ in range(num_stocks)]
|
||||
num_minions = stream.read_dword()
|
||||
self.hireling_minions = [MinionElement() for _ in range(num_minions)]
|
||||
num_servies = stream.read_dword()
|
||||
self.hireling_servies = [ServiceElement() for _ in range(num_servies)]
|
||||
num_orders = stream.read_dword()
|
||||
self.hireling_orders = [[
|
||||
stream.read_dword() for _ in range(4)
|
||||
] for _ in range(num_orders)]
|
||||
num_starting_formulas = stream.read_dword()
|
||||
self.hireling_starting_formulas = [stream.read_qword() for _ in range(num_starting_formulas)]
|
||||
num_valid_formula_types = stream.read_dword()
|
||||
self.hireling_valid_formula_types = [stream.read_dword() for _ in range(num_valid_formula_types)]
|
||||
num_valid_formula_categories = stream.read_dword()
|
||||
self.hireling_valid_formula_category = [stream.read_dword() for _ in range(num_valid_formula_categories)]
|
||||
num_enchantment_types = stream.read_dword()
|
||||
self.hireling_enchantment_types = [stream.read_dword() for _ in range(num_enchantment_types)]
|
||||
num_valid_weapons = stream.read_dword()
|
||||
self.hireling_valid_weapons = [stream.read_dword() for _ in range(num_valid_weapons)]
|
||||
num_valid_armors = stream.read_dword()
|
||||
self.hireling_valid_armors = [stream.read_dword() for _ in range(num_valid_armors)]
|
||||
num_valid_slaves = stream.read_dword()
|
||||
self.hireling_valid_slaves = [stream.read_dword() for _ in range(num_valid_slaves)]
|
||||
num_mods = stream.read_dword()
|
||||
self.hireling_mods = [HirelingMod() for _ in range(num_mods)]
|
||||
for mod in self.hireling_mods:
|
||||
mod.load_binary(stream)
|
||||
self.hireling_max_items_stocked = stream.read_dword()
|
||||
self.hireling_has_junker = stream.read_bool()
|
||||
if self.hireling_has_junker:
|
||||
self.hireling_junker = JunkerBasics()
|
||||
self.hireling_junker.load_binary(stream)
|
||||
@@ -0,0 +1,50 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from arcane.util import ResStream
|
||||
from .MobileInfo import MobileInfo
|
||||
|
||||
|
||||
class MerchantInfo(MobileInfo):
|
||||
def load_binary(self, stream: ResStream):
|
||||
super().load_binary(stream)
|
||||
self.merchant_trade_type = stream.read_dword()
|
||||
self.merchant_std_buy_margin = stream.read_float()
|
||||
self.merchant_std_sell_margin = stream.read_float()
|
||||
self.merchant_guild_buy_margin = stream.read_float()
|
||||
self.merchant_guild_sell_margin = stream.read_float()
|
||||
self.merchant_nation_buy_margin = stream.read_float()
|
||||
self.merchant_nation_sell_margin = stream.read_float()
|
||||
num_buy_list = stream.read_dword()
|
||||
self.merchant_buy_list = [[
|
||||
stream.read_qword(),
|
||||
stream.read_dword(),
|
||||
] for _ in range(num_buy_list)]
|
||||
num_sell_list = stream.read_dword()
|
||||
self.merchant_sell_list = [[
|
||||
stream.read_qword(),
|
||||
stream.read_dword(),
|
||||
] for _ in range(num_sell_list)]
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
super().save_binary(stream)
|
||||
stream.write_dword(self.merchant_trade_type)
|
||||
stream.write_float(self.merchant_std_buy_margin)
|
||||
stream.write_float(self.merchant_std_sell_margin)
|
||||
stream.write_float(self.merchant_guild_buy_margin)
|
||||
stream.write_float(self.merchant_guild_sell_margin)
|
||||
stream.write_float(self.merchant_nation_buy_margin)
|
||||
stream.write_float(self.merchant_nation_sell_margin)
|
||||
stream.write_dword(len(self.merchant_buy_list))
|
||||
for l in self.merchant_buy_list:
|
||||
stream.write_qword(l[0])
|
||||
stream.write_dword(l[1])
|
||||
stream.write_dword(len(self.merchant_sell_list))
|
||||
for l in self.merchant_sell_list:
|
||||
stream.write_qword(l[0])
|
||||
stream.write_dword(l[1])
|
||||
@@ -0,0 +1,16 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from arcane.util import ResStream
|
||||
from .HirelingInfo import HirelingInfo
|
||||
|
||||
|
||||
class MinionInfo(HirelingInfo):
|
||||
def load_binary(self, stream: ResStream):
|
||||
super().load_binary(stream)
|
||||
self.minion_info_u = stream.read_string()
|
||||
@@ -0,0 +1,340 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from arcane.enums.arc_rune import *
|
||||
from arcane.enums.hashes import hash_to_string, string_to_hash
|
||||
from arcane.objects.ArcRune import Group
|
||||
from arcane.objects.common.Inventory import Inventory
|
||||
from arcane.util import ResStream
|
||||
from .ArcBasicZoneObjectInfo import ArcBasicZoneObjectInfo
|
||||
|
||||
|
||||
class Unknown:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.unknown_u = stream.read_dword()
|
||||
self.unknown_u = stream.read_dword()
|
||||
self.unknown_u = stream.read_dword()
|
||||
self.unknown_check = stream.read_bool()
|
||||
if self.unknown_check:
|
||||
self.unknown_u = stream.read_qword()
|
||||
else:
|
||||
self.unknown_u = stream.read_dword()
|
||||
self.unknown_u = stream.read_string()
|
||||
self.unknown_u = stream.read_float()
|
||||
|
||||
|
||||
class InventoryContents:
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.mobile_inventory_u = stream.read_qword()
|
||||
self.mobile_inventory_u = stream.read_qword()
|
||||
self.mobile_inventory_u = stream.read_tuple()
|
||||
self.mobile_inventory_u = stream.read_tuple()
|
||||
self.mobile_inventory_u = [stream.read_float() for _ in range(4)]
|
||||
self.mobile_inventory_u = stream.read_qword()
|
||||
self.mobile_inventory_u = stream.read_dword()
|
||||
self.mobile_inventory_u = stream.read_dword()
|
||||
self.mobile_inventory_u = stream.read_dword()
|
||||
self.mobile_inventory_u = stream.read_bool()
|
||||
self.mobile_inventory_u = stream.read_string()
|
||||
self.mobile_inventory_check = stream.read_bool()
|
||||
if self.mobile_inventory_check:
|
||||
self.mobile_inventory_u = stream.read_float()
|
||||
self.mobile_inventory_u = stream.read_float()
|
||||
self.mobile_inventory_check = stream.read_bool()
|
||||
if self.mobile_inventory_check:
|
||||
self.mobile_inventory_u = stream.read_qword()
|
||||
self.mobile_inventory_u = stream.read_dword()
|
||||
self.mobile_inventory_u = stream.read_dword()
|
||||
self.mobile_inventory_u = stream.read_float()
|
||||
self.mobile_inventory_u = stream.read_dword()
|
||||
self.mobile_inventory_u = stream.read_dword()
|
||||
num = stream.read_dword()
|
||||
self.mobile_inventory_u = [Unknown() for _ in range(num)]
|
||||
self.mobile_inventory_u = stream.read_dword()
|
||||
self.mobile_inventory_check = stream.read_bool()
|
||||
if self.mobile_inventory_check:
|
||||
self.mobile_inventory_u = stream.read_qword()
|
||||
self.mobile_inventory_u = stream.read_qword()
|
||||
self.mobile_inventory_u = stream.read_qword()
|
||||
self.mobile_inventory_u = stream.read_dword()
|
||||
self.mobile_inventory_check = stream.read_bool()
|
||||
if self.mobile_inventory_check:
|
||||
self.mobile_inventory_u = stream.read_qword()
|
||||
self.mobile_inventory_u = stream.read_dword()
|
||||
self.mobile_inventory_check = stream.read_bool()
|
||||
if self.mobile_inventory_check:
|
||||
self.mobile_inventory_u = stream.read_bool()
|
||||
self.mobile_inventory_u = stream.read_float()
|
||||
self.mobile_inventory_u = stream.read_dword()
|
||||
self.mobile_inventory_u = stream.read_dword()
|
||||
self.mobile_inventory_check = stream.read_bool()
|
||||
if self.mobile_inventory_check:
|
||||
self.mobile_inventory_u = [stream.read_dword() for _ in range(5)]
|
||||
self.mobile_inventory_check = stream.read_bool()
|
||||
if self.mobile_inventory_check:
|
||||
self.mobile_inventory_u = [stream.read_dword() for _ in range(5)]
|
||||
self.mobile_inventory_u = stream.read_bool()
|
||||
|
||||
|
||||
class MobileInfo:
|
||||
|
||||
def load_binary(self, stream: ResStream):
|
||||
self.mobile_base_zone = ArcBasicZoneObjectInfo()
|
||||
self.mobile_base_zone.load_binary(stream)
|
||||
self.mobile_number_in_group = stream.read_dword()
|
||||
self.mobile_change_to_find = stream.read_float()
|
||||
self.mobile_level = stream.read_dword()
|
||||
self.mobile_behavior_file = stream.read_string()
|
||||
self.mobile_dialog_override = stream.read_dword()
|
||||
self.mobile_base_exp_reward = stream.read_dword()
|
||||
self.mobile_tenacity = stream.read_float()
|
||||
self.mobile_courage = stream.read_float()
|
||||
self.mobile_has_group_tactics = stream.read_bool()
|
||||
if self.mobile_has_group_tactics:
|
||||
self.mobile_group_tactics = stream.read_dword()
|
||||
self.mobile_has_role_set = stream.read_bool()
|
||||
if self.mobile_has_role_set:
|
||||
self.mobile_role_set = stream.read_dword()
|
||||
self.mobile_has_home_goal = stream.read_bool()
|
||||
if self.mobile_has_home_goal:
|
||||
self.mobile_home_goal = stream.read_dword()
|
||||
self.mobile_spawn_home_goal = stream.read_bool()
|
||||
self.mobile_has_target_goal = stream.read_bool()
|
||||
if self.mobile_has_target_goal:
|
||||
self.mobile_target_goal = stream.read_dword()
|
||||
self.mobile_spawn_target_goal = stream.read_bool()
|
||||
num_rune_stone_ids = stream.read_dword()
|
||||
self.mobile_rune_stone_ids = [stream.read_qword() for _ in range(num_rune_stone_ids)]
|
||||
self.mobile_has_content = stream.read_bool()
|
||||
if self.mobile_has_content:
|
||||
num_contents = stream.read_dword()
|
||||
self.mobile_inventory_contents = [InventoryContents() for _ in range(num_contents)]
|
||||
for content in self.mobile_inventory_contents:
|
||||
content.load_binary(stream)
|
||||
num_equipments = stream.read_dword()
|
||||
self.mobile_equipment = [[
|
||||
stream.read_qword(),
|
||||
stream.read_float(),
|
||||
] for _ in range(num_equipments)]
|
||||
num_lores = stream.read_dword()
|
||||
self.mobile_lores = [stream.read_dword() for _ in range(num_lores)]
|
||||
self.mobile_use_prefered_hp = stream.read_bool()
|
||||
num_spawn_hps = stream.read_dword()
|
||||
self.mobile_spawn_hps = [stream.read_dword() for _ in range(num_spawn_hps)]
|
||||
num = stream.read_dword()
|
||||
self.mobile_booties = [Inventory() for _ in range(num)]
|
||||
for booty in self.mobile_booties:
|
||||
booty.load_binary(stream)
|
||||
self.mobile_root_fs_mid = stream.read_string()
|
||||
self.mobile_group = Group()
|
||||
self.mobile_group.load_binary(stream)
|
||||
num_enemy_monster_types = stream.read_dword()
|
||||
self.mobile_enemy_monster_types = [stream.read_dword() for _ in range(num_enemy_monster_types)]
|
||||
num_not_enemy_monster_types = stream.read_dword()
|
||||
self.mobile_not_enemy_monster_types = [stream.read_dword() for _ in range(num_not_enemy_monster_types)]
|
||||
num_groupee_monster_types = stream.read_dword()
|
||||
self.mobile_groupee_monster_types = [stream.read_dword() for _ in range(num_groupee_monster_types)]
|
||||
num_helper_monster_types = stream.read_dword()
|
||||
self.mobile_helper_monster_types = [stream.read_dword() for _ in range(num_helper_monster_types)]
|
||||
num_enemy_genders = stream.read_dword()
|
||||
self.mobile_enemy_genders = [stream.read_dword() for _ in range(num_enemy_genders)]
|
||||
num_firendly_charters = stream.read_dword()
|
||||
self.mobile_firendly_charters = [stream.read_dword() for _ in range(num_firendly_charters)]
|
||||
self.mobile_parley_name = stream.read_string()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
self.mobile_base_zone.save_binary(stream)
|
||||
stream.write_dword(self.mobile_number_in_group)
|
||||
stream.write_float(self.mobile_change_to_find)
|
||||
stream.write_dword(self.mobile_level)
|
||||
stream.write_string(self.mobile_behavior_file)
|
||||
stream.write_dword(self.mobile_dialog_override)
|
||||
stream.write_dword(self.mobile_base_exp_reward)
|
||||
stream.write_float(self.mobile_tenacity)
|
||||
stream.write_float(self.mobile_courage)
|
||||
stream.write_bool(self.mobile_has_group_tactics)
|
||||
if self.mobile_has_group_tactics:
|
||||
stream.write_dword(self.mobile_group_tactics)
|
||||
stream.write_bool(self.mobile_has_role_set)
|
||||
if self.mobile_has_role_set:
|
||||
stream.write_dword(self.mobile_role_set)
|
||||
stream.write_bool(self.mobile_has_home_goal)
|
||||
if self.mobile_has_home_goal:
|
||||
stream.write_dword(self.mobile_home_goal)
|
||||
stream.write_bool(self.mobile_spawn_home_goal)
|
||||
stream.write_bool(self.mobile_has_target_goal)
|
||||
if self.mobile_has_target_goal:
|
||||
stream.write_dword(self.mobile_target_goal)
|
||||
stream.write_bool(self.mobile_spawn_target_goal)
|
||||
stream.write_dword(len(self.mobile_rune_stone_ids))
|
||||
for rune_stone_id in self.mobile_rune_stone_ids:
|
||||
stream.write_qword(rune_stone_id)
|
||||
stream.write_bool(self.mobile_has_content)
|
||||
if self.mobile_has_content:
|
||||
stream.write_dword(len(self.mobile_inventory_contents))
|
||||
for content in self.mobile_inventory_contents:
|
||||
content.save_binary(stream)
|
||||
stream.write_dword(len(self.mobile_equipment))
|
||||
for equipment in self.mobile_equipment:
|
||||
stream.write_qword(equipment[0])
|
||||
stream.write_float(equipment[1])
|
||||
stream.write_dword(len(self.mobile_lores))
|
||||
for lore in self.mobile_lores:
|
||||
stream.write_dword(lore)
|
||||
stream.write_bool(self.mobile_use_prefered_hp)
|
||||
stream.write_dword(len(self.mobile_spawn_hps))
|
||||
for spawn_hp in self.mobile_spawn_hps:
|
||||
stream.write_dword(spawn_hp)
|
||||
stream.write_dword(len(self.mobile_booties))
|
||||
for booty in self.mobile_booties:
|
||||
booty.save_binary(stream)
|
||||
stream.write_string(self.mobile_root_fs_mid)
|
||||
self.mobile_group.save_binary(stream)
|
||||
stream.write_dword(len(self.mobile_enemy_monster_types))
|
||||
for enemy_monster_type in self.mobile_enemy_monster_types:
|
||||
stream.write_dword(enemy_monster_type)
|
||||
stream.write_dword(len(self.mobile_not_enemy_monster_types))
|
||||
for not_enemy_monster_type in self.mobile_not_enemy_monster_types:
|
||||
stream.write_dword(not_enemy_monster_type)
|
||||
stream.write_dword(len(self.mobile_groupee_monster_types))
|
||||
for groupee_monster_type in self.mobile_groupee_monster_types:
|
||||
stream.write_dword(groupee_monster_type)
|
||||
stream.write_dword(len(self.mobile_helper_monster_types))
|
||||
for helper_monster_type in self.mobile_helper_monster_types:
|
||||
stream.write_dword(helper_monster_type)
|
||||
stream.write_dword(len(self.mobile_enemy_genders))
|
||||
for enemy_gender in self.mobile_enemy_genders:
|
||||
stream.write_dword(enemy_gender)
|
||||
stream.write_dword(len(self.mobile_firendly_charters))
|
||||
for firendly_charter in self.mobile_firendly_charters:
|
||||
stream.write_dword(firendly_charter)
|
||||
stream.write_string(self.mobile_parley_name)
|
||||
|
||||
def save_json(self):
|
||||
data = OrderedDict()
|
||||
data['mobile_base_zone'] = self.mobile_base_zone.save_json()
|
||||
data['mobile_number_in_group'] = self.mobile_number_in_group
|
||||
data['mobile_change_to_find'] = self.mobile_change_to_find
|
||||
data['mobile_level'] = self.mobile_level
|
||||
data['mobile_behavior_file'] = self.mobile_behavior_file
|
||||
data['mobile_dialog_override'] = self.mobile_dialog_override
|
||||
data['mobile_base_exp_reward'] = self.mobile_base_exp_reward
|
||||
data['mobile_tenacity'] = self.mobile_tenacity
|
||||
data['mobile_courage'] = self.mobile_courage
|
||||
data['mobile_has_group_tactics'] = self.mobile_has_group_tactics
|
||||
if self.mobile_has_group_tactics:
|
||||
data['mobile_group_tactics'] = self.mobile_group_tactics
|
||||
data['mobile_has_role_set'] = self.mobile_has_role_set
|
||||
if self.mobile_has_role_set:
|
||||
data['mobile_role_set'] = self.mobile_role_set
|
||||
data['mobile_has_home_goal'] = self.mobile_has_home_goal
|
||||
if self.mobile_has_home_goal:
|
||||
data['mobile_home_goal'] = self.mobile_home_goal
|
||||
data['mobile_spawn_home_goal'] = self.mobile_spawn_home_goal
|
||||
data['mobile_has_target_goal'] = self.mobile_has_target_goal
|
||||
if self.mobile_has_target_goal:
|
||||
data['mobile_target_goal'] = self.mobile_target_goal
|
||||
data['mobile_spawn_target_goal'] = self.mobile_spawn_target_goal
|
||||
data['mobile_rune_stone_ids'] = self.mobile_rune_stone_ids
|
||||
data['mobile_has_content'] = self.mobile_has_content
|
||||
if self.mobile_has_content:
|
||||
data['mobile_inventory_contents'] = []
|
||||
for content in self.mobile_inventory_contents:
|
||||
data['mobile_inventory_contents'].append(content.save_json())
|
||||
data['mobile_equipment'] = self.mobile_equipment
|
||||
data['mobile_lores'] = self.mobile_lores
|
||||
data['mobile_use_prefered_hp'] = self.mobile_use_prefered_hp
|
||||
data['mobile_spawn_hps'] = self.mobile_spawn_hps
|
||||
data['mobile_booties'] = []
|
||||
for booty in self.mobile_booties:
|
||||
data['mobile_booties'].append(booty.save_json())
|
||||
data['mobile_root_fs_mid'] = self.mobile_root_fs_mid
|
||||
data['mobile_group'] = self.mobile_group.save_json()
|
||||
data['mobile_enemy_monster_types'] = []
|
||||
for enemy_monster_type in self.mobile_enemy_monster_types:
|
||||
data['mobile_enemy_monster_types'].append(hash_to_string(enemy_monster_type))
|
||||
data['mobile_not_enemy_monster_types'] = []
|
||||
for not_enemy_monster_type in self.mobile_not_enemy_monster_types:
|
||||
data['mobile_not_enemy_monster_types'].append(hash_to_string(not_enemy_monster_type))
|
||||
data['mobile_groupee_monster_types'] = []
|
||||
for groupee_monster_type in self.mobile_groupee_monster_types:
|
||||
data['mobile_groupee_monster_types'].append(hash_to_string(groupee_monster_type))
|
||||
data['mobile_helper_monster_types'] = []
|
||||
for helper_monster_type in self.mobile_helper_monster_types:
|
||||
data['mobile_helper_monster_types'].append(hash_to_string(helper_monster_type))
|
||||
data['mobile_enemy_genders'] = []
|
||||
for enemy_gender in self.mobile_enemy_genders:
|
||||
data['mobile_enemy_genders'].append(RUNE_SEX_TO_STRING[enemy_gender])
|
||||
data['mobile_firendly_charters'] = self.mobile_firendly_charters
|
||||
data['mobile_parley_name'] = self.mobile_parley_name
|
||||
return data
|
||||
|
||||
def load_json(self, data):
|
||||
self.mobile_base_zone = ArcBasicZoneObjectInfo()
|
||||
self.mobile_base_zone.load_json(data['mobile_base_zone'])
|
||||
self.mobile_number_in_group = data['mobile_number_in_group']
|
||||
self.mobile_change_to_find = data['mobile_change_to_find']
|
||||
self.mobile_level = data['mobile_level']
|
||||
self.mobile_behavior_file = data['mobile_behavior_file']
|
||||
self.mobile_dialog_override = data['mobile_dialog_override']
|
||||
self.mobile_base_exp_reward = data['mobile_base_exp_reward']
|
||||
self.mobile_tenacity = data['mobile_tenacity']
|
||||
self.mobile_courage = data['mobile_courage']
|
||||
self.mobile_has_group_tactics = data['mobile_has_group_tactics']
|
||||
if self.mobile_has_group_tactics:
|
||||
self.mobile_group_tactics = data['mobile_group_tactics']
|
||||
self.mobile_has_role_set = data['mobile_has_role_set']
|
||||
if self.mobile_has_role_set:
|
||||
self.mobile_role_set = data['mobile_role_set']
|
||||
self.mobile_has_home_goal = data['mobile_has_home_goal']
|
||||
if self.mobile_has_home_goal:
|
||||
self.mobile_home_goal = data['mobile_home_goal']
|
||||
self.mobile_spawn_home_goal = data['mobile_spawn_home_goal']
|
||||
self.mobile_has_target_goal = data['mobile_has_target_goal']
|
||||
if self.mobile_has_target_goal:
|
||||
self.mobile_target_goal = data['mobile_target_goal']
|
||||
self.mobile_spawn_target_goal = data['mobile_spawn_target_goal']
|
||||
self.mobile_rune_stone_ids = data['mobile_rune_stone_ids']
|
||||
self.mobile_has_content = data['mobile_has_content']
|
||||
if self.mobile_has_content:
|
||||
self.mobile_inventory_contents = []
|
||||
for content_data in data['mobile_inventory_contents']:
|
||||
content = InventoryContents()
|
||||
content.load_json(content_data)
|
||||
self.mobile_inventory_contents.append(content)
|
||||
self.mobile_equipment = data['mobile_equipment']
|
||||
self.mobile_lores = data['mobile_lores']
|
||||
self.mobile_use_prefered_hp = data['mobile_use_prefered_hp']
|
||||
self.mobile_spawn_hps = data['mobile_spawn_hps']
|
||||
self.mobile_booties = []
|
||||
for booty_data in data['mobile_booties']:
|
||||
booty = Inventory()
|
||||
booty.load_json(booty_data)
|
||||
self.mobile_booties.append(booty)
|
||||
self.mobile_root_fs_mid = data['mobile_root_fs_mid']
|
||||
self.mobile_group = Group()
|
||||
self.mobile_group.load_json(data['mobile_group'])
|
||||
self.mobile_enemy_monster_types = []
|
||||
for enemy_monster_type in data['mobile_enemy_monster_types']:
|
||||
self.mobile_enemy_monster_types.append(string_to_hash(enemy_monster_type))
|
||||
self.mobile_not_enemy_monster_types = []
|
||||
for not_enemy_monster_type in data['mobile_not_enemy_monster_types']:
|
||||
self.mobile_not_enemy_monster_types.append(string_to_hash(not_enemy_monster_type))
|
||||
self.mobile_groupee_monster_types = []
|
||||
for groupee_monster_type in data['mobile_groupee_monster_types']:
|
||||
self.mobile_groupee_monster_types.append(string_to_hash(groupee_monster_type))
|
||||
self.mobile_helper_monster_types = []
|
||||
for helper_monster_type in data['mobile_helper_monster_types']:
|
||||
self.mobile_helper_monster_types.append(string_to_hash(helper_monster_type))
|
||||
self.mobile_enemy_genders = []
|
||||
for enemy_gender in data['mobile_enemy_genders']:
|
||||
self.mobile_enemy_genders.append(STRING_TO_RUNE_SEX[enemy_gender])
|
||||
self.mobile_firendly_charters = data['mobile_firendly_charters']
|
||||
self.mobile_parley_name = data['mobile_parley_name']
|
||||
@@ -0,0 +1,48 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from arcane.util import ResStream
|
||||
from .MobileInfo import MobileInfo
|
||||
|
||||
|
||||
class ShopKeeperInfo(MobileInfo):
|
||||
def load_binary(self, stream: ResStream):
|
||||
super().load_binary(stream)
|
||||
self.shopkeeper_shop_type = stream.read_dword()
|
||||
self.shopkeeper_start_gold = stream.read_dword()
|
||||
self.shopkeeper_std_buy_percent = stream.read_float()
|
||||
self.shopkeeper_std_sell_percent = stream.read_float()
|
||||
self.shopkeeper_nation_buy_percent = stream.read_float()
|
||||
self.shopkeeper_nation_sell_percent = stream.read_float()
|
||||
num_buy_list = stream.read_dword()
|
||||
self.shopkeeper_buy_list = [[
|
||||
stream.read_qword(),
|
||||
stream.read_dword(),
|
||||
] for _ in range(num_buy_list)]
|
||||
num_sell_list = stream.read_dword()
|
||||
self.shopkeeper_sell_list = [[
|
||||
stream.read_qword(),
|
||||
stream.read_dword(),
|
||||
] for _ in range(num_sell_list)]
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
super().save_binary(stream)
|
||||
stream.write_dword(self.shopkeeper_shop_type)
|
||||
stream.write_dword(self.shopkeeper_start_gold)
|
||||
stream.write_float(self.shopkeeper_std_buy_percent)
|
||||
stream.write_float(self.shopkeeper_std_sell_percent)
|
||||
stream.write_float(self.shopkeeper_nation_buy_percent)
|
||||
stream.write_float(self.shopkeeper_nation_sell_percent)
|
||||
stream.write_dword(len(self.shopkeeper_buy_list))
|
||||
for l in self.shopkeeper_buy_list:
|
||||
stream.write_qword(l[0])
|
||||
stream.write_dword(l[1])
|
||||
stream.write_dword(len(self.shopkeeper_sell_list))
|
||||
for l in self.shopkeeper_sell_list:
|
||||
stream.write_qword(l[0])
|
||||
stream.write_dword(l[1])
|
||||
@@ -0,0 +1,33 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
|
||||
from arcane.util import ResStream
|
||||
from .MobileInfo import MobileInfo
|
||||
|
||||
|
||||
class TrainerInfo(MobileInfo):
|
||||
def load_binary(self, stream: ResStream):
|
||||
super().load_binary(stream)
|
||||
self.trainer_std_profit_margin = stream.read_float()
|
||||
self.trainer_profit_margin = stream.read_float()
|
||||
|
||||
def save_binary(self, stream: ResStream):
|
||||
super().save_binary(stream)
|
||||
stream.write_float(self.trainer_std_profit_margin)
|
||||
stream.write_float(self.trainer_profit_margin)
|
||||
|
||||
def save_json(self):
|
||||
data = super().save_json()
|
||||
data['trainer_std_profit_margin'] = self.trainer_std_profit_margin
|
||||
data['trainer_profit_margin'] = self.trainer_profit_margin
|
||||
return data
|
||||
|
||||
def load_json(self, data):
|
||||
super().load_json(data)
|
||||
self.trainer_std_profit_margin = data['trainer_std_profit_margin']
|
||||
self.trainer_profit_margin = data['trainer_profit_margin']
|
||||
@@ -0,0 +1,7 @@
|
||||
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||||
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||||
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||||
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||||
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||||
# Magicbane Emulator Project © 2013 - 2022
|
||||
# www.magicbane.com
|
||||
Reference in New Issue
Block a user