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.
396 lines
19 KiB
396 lines
19 KiB
# • ▌ ▄ ·. ▄▄▄▄· ▄▄▄ .·▄▄▄▄ ▪ ▄▄▄▄▄ ▄▄▄ ▄▄▄·▄▄▄ |
|
# ·██ ▐███▪▐█ ▀█▪ ▀▄.▀·██▪ ██ ██ •██ ▪ ▀▄ █· ▐█ ▄█▀▄ █·▪ |
|
# ▐█ ▌▐▌▐█·▐█▀▀█▄ ▐▀▀▪▄▐█· ▐█▌▐█· ▐█.▪ ▄█▀▄ ▐▀▀▄ ██▀·▐▀▀▄ ▄█▀▄ |
|
# ██ ██▌▐█▌██▄▪▐█ ▐█▄▄▌██. ██ ▐█▌ ▐█▌·▐█▌.▐▌▐█•█▌ ▐█▪·•▐█•█▌▐█▌.▐▌ |
|
# ▀▀ █▪▀▀▀·▀▀▀▀ ▀▀▀ ▀▀▀▀▀• ▀▀▀ ▀▀▀ ▀█▄▀▪.▀ ▀ .▀ .▀ ▀ ▀█▄▀▪ |
|
# 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
|
|
|