mbEditorPro2.0 release

This commit is contained in:
2022-12-25 08:47:00 -05:00
parent 30375c8413
commit 942b33a252
110 changed files with 3543 additions and 1089 deletions
+70
View File
@@ -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()}
+113
View File
@@ -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
+89
View File
@@ -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
+644
View File
@@ -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
+125
View File
@@ -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
+40
View File
@@ -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)
+242
View File
@@ -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
+396
View File
@@ -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
+7
View File
@@ -0,0 +1,7 @@
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
# Magicbane Emulator Project © 2013 - 2022
# www.magicbane.com
+7
View File
@@ -0,0 +1,7 @@
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
# Magicbane Emulator Project © 2013 - 2022
# www.magicbane.com
+62
View File
@@ -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,
}
+49
View File
@@ -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,
}
+332
View File
@@ -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,
}
+180
View File
@@ -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,
}
+69
View File
@@ -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,
}
+291
View File
@@ -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
+83
View File
@@ -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
+517
View File
@@ -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
+41
View File
@@ -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
+148
View File
@@ -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
+469
View File
@@ -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
+21
View File
@@ -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
+116
View File
@@ -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])
+108
View File
@@ -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()
+10
View File
@@ -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
+47
View File
@@ -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)
+19
View File
@@ -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']
+79
View File
@@ -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'])
+270
View File
@@ -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']
+408
View File
@@ -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']
+92
View File
@@ -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']
+9
View File
@@ -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