You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
397 lines
19 KiB
397 lines
19 KiB
2 years ago
|
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄
|
||
|
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪
|
||
|
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄
|
||
|
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌
|
||
|
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪
|
||
|
# 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
|