/* by korenkonder GitHub/GitLab: korenkonder */ #include "rob.hpp" #include "../../KKdLib/str_utils.hpp" #include "../mdl/disp_manager.hpp" #include "../gl_state.hpp" #include "../object.hpp" #include "../render_manager.hpp" #include #include enum ExNodeType { EX_NONE = 0x00, EX_OSAGE = 0x01, EX_EXPRESSION = 0x02, EX_CONSTRAINT = 0x03, EX_CLOTH = 0x04, }; enum rob_chara_data_hand_adjust_type : uint16_t { ROB_CHARA_DATA_HAND_ADJUST_NONE = (uint16_t)-1, ROB_CHARA_DATA_HAND_ADJUST_NORMAL = 0x00, ROB_CHARA_DATA_HAND_ADJUST_SHORT = 0x01, ROB_CHARA_DATA_HAND_ADJUST_TALL = 0x02, ROB_CHARA_DATA_HAND_ADJUST_MIN = 0x03, ROB_CHARA_DATA_HAND_ADJUST_MAX = 0x04, ROB_CHARA_DATA_HAND_ADJUST_OPPOSITE_CHARA = 0x05, ROB_CHARA_DATA_HAND_ADJUST_CUSTOM = 0x06, ROB_CHARA_DATA_HAND_ADJUST_1P = 0x07, ROB_CHARA_DATA_HAND_ADJUST_2P = 0x08, ROB_CHARA_DATA_HAND_ADJUST_3P = 0x09, ROB_CHARA_DATA_HAND_ADJUST_4P = 0x0A, ROB_CHARA_DATA_HAND_ADJUST_ITEM = 0x0F, // X }; struct rob_chara_age_age_object_vertex { vec3 position; vec3 normal; vec4 tangent; vec2 texcoord; }; static_assert(sizeof(rob_chara_age_age_object_vertex) == 0x30, "\"rob_chara_age_age_object_vertex\" struct should have a size of 0x30"); struct rob_chara_age_age_object { void* objset_info; // ObjsetInfo int32_t obj_index; int32_t field_C; int32_t num_vertex; int32_t num_index; obj obj; obj_mesh mesh; obj_sub_mesh sub_mesh; obj_material_data material[2]; obj_axis_aligned_bounding_box axis_aligned_bounding_box; rob_chara_age_age_object_vertex* vertex_data; int32_t vertex_data_size; int32_t vertex_array_size; #if SHARED_OBJECT_BUFFER obj_mesh_vertex_buffer_aft obj_vert_buf; #else obj_mesh_vertex_buffer obj_vert_buf; #endif obj_mesh_index_buffer obj_index_buf; vec3 trans[10]; int32_t disp_count; int32_t count; bool field_C3C; void disp(size_t chara_index, bool npr, bool reflect, const vec3& a5, bool chara_color); }; static_assert(sizeof(rob_chara_age_age_object) == 0xC40, "\"rob_chara_age_age_object\" struct should have a size of 0xC40"); struct rob_chara_age_age_data { int32_t index; int32_t part_id; vec3 trans; float_t field_14; float_t rot_z; int32_t field_1C; float_t rot_speed; float_t gravity; float_t scale; float_t alpha; mat4 mat_scale; mat4 mat; mat4 prev_parent_mat; float_t remaining; bool alive; }; static_assert(sizeof(rob_chara_age_age_data) == 0xF8, "\"rob_chara_age_age_data\" struct should have a size of 0xF8"); struct rob_chara_age_age { rob_chara_age_age_data data[10]; float_t frame; float_t field_9B4; mat4 mat; float_t step; bool visible; bool skip; float_t move_cancel; float_t alpha; rob_chara_age_age_object object; bool npr; float_t rot_speed; bool step_full; void disp(size_t chara_id, bool npr, bool reflect, const vec3& a5, bool chara_color); }; static_assert(sizeof(rob_chara_age_age) == 0x1658, "\"rob_chara_age_age\" struct should have a size of 0x1658"); struct bone_node_expression_data { vec3 position; vec3 rotation; vec3 scale; vec3 parent_scale; }; static_assert(sizeof(bone_node_expression_data) == 0x30, "\"bone_node_expression_data\" struct should have a size of 0x30"); struct bone_node { const char* name; mat4* mat; bone_node* parent; bone_node_expression_data exp_data; mat4* ex_data_mat; }; static_assert(sizeof(bone_node) == 0x50, "\"bone_node\" struct should have a size of 0x50"); struct opd_blend_data { int32_t motion_id; float_t frame; float_t frame_count; bool use_blend; int32_t type; // MotionBlendType float_t blend; }; static_assert(sizeof(opd_blend_data) == 0x18, "\"opd_blend_data\" struct should have a size of 0x18"); struct ExNodeBlock; struct ExNodeBlock_vtbl { ExNodeBlock* (FASTCALL* Dispose)(ExNodeBlock* node, uint8_t); void(FASTCALL* Field8)(ExNodeBlock* node); void(FASTCALL* Field10)(ExNodeBlock* node); void(FASTCALL* Field18)(ExNodeBlock* node, int32_t stage, bool disable_external_force); void(FASTCALL* Field20)(ExNodeBlock* node); void(FASTCALL* SetOsagePlayData)(ExNodeBlock* node); void(FASTCALL* Disp)(ExNodeBlock* node); void(FASTCALL* Reset)(ExNodeBlock* node); void(FASTCALL* Field40)(ExNodeBlock* node); void(FASTCALL* Field48)(ExNodeBlock* node); void(FASTCALL* Field50)(ExNodeBlock* node); void(FASTCALL* Field58)(ExNodeBlock* node); }; struct rob_chara_item_equip_object; struct ExNodeBlock { ExNodeBlock_vtbl* __vftable; bone_node* bone_node_ptr; ExNodeType type; const char* name; bone_node* parent_bone_node; prj::string parent_name; ExNodeBlock* parent_node; rob_chara_item_equip_object* item_equip_object; bool field_58; bool field_59; bool has_children_node; }; struct rob_chara_item_equip; struct rob_chara_item_equip_object { size_t index; mat4* mats; object_info obj_info; int32_t field_14; prj::vector texture_pattern; texture_data_struct texture_data; bool null_blocks_data_set; bone_node_expression_data exp_data; float_t alpha; mdl::ObjFlags obj_flags; bool can_disp; int32_t field_A4; mat4* mat; int32_t osage_iterations; bone_node* bone_nodes; prj::vector node_blocks; prj::vector ex_data_bone_nodes; prj::vector ex_data_bone_mats; prj::vector ex_data_mats; prj::vector> ex_bones; int64_t field_138; prj::vector null_blocks; // ExNullBlock prj::vector osage_blocks; // ExOsageBlock prj::vector constraint_blocks; // ExConstraintBlock prj::vector expression_blocks; // ExExpressionBlock prj::vector cloth_blocks; // ExClothBlock bool field_1B8; size_t osage_nodes_count; bool use_opd; obj_skin_ex_data* skin_ex_data; obj_skin* skin; rob_chara_item_equip* item_equip; void disp(const mat4* mat); int32_t get_bone_index(const char* name); bone_node* get_bone_node(int32_t bone_index); bone_node* get_bone_node(const char* name); }; static_assert(sizeof(rob_chara_item_equip_object) == 0x1E8, "\"rob_chara_item_equip_object\" struct should have a size of 0x1E8"); struct rob_chara_item_equip { bone_node* bone_nodes; mat4* matrices; rob_chara_item_equip_object* item_equip_object; int32_t field_18[31]; bool item_equip_range; item_id first_item_equip_object; item_id max_item_equip_object; int32_t field_A0; shadow_type_enum shadow_type; vec3 position; prj::vector texture_pattern; object_info field_D0; item_id field_D4; bool disable_update; int32_t field_DC; vec4 texture_color_coefficients; float_t wet; float_t wind_strength; bool chara_color; bool npr_flag; mat4 mat; mat4 field_13C[30]; int32_t field_8BC; int32_t field_8C0; int32_t field_8C4; int32_t field_8C8; int32_t field_8CC; int32_t field_8D0; int32_t field_8D4; int32_t field_8D8; int32_t field_8DC; int32_t field_8E0; int32_t field_8E4; int32_t field_8E8; int32_t field_8EC; int32_t field_8F0; int32_t field_8F4; int32_t field_8F8; int32_t field_8FC; int64_t field_900; int64_t field_908; int64_t field_910; int64_t field_918; int64_t field_920; int64_t field_928; int64_t field_930; float_t osage_step; bool use_opd; prj::vector opd_blend_data; bool parts_short; bool parts_append; bool parts_white_one_l; }; static_assert(sizeof(rob_chara_item_equip) == 0x960, "\"rob_chara_item_equip\" struct should have a size of 0x960"); struct rob_chara_item_cos_data { uint8_t data[0x408]; }; static_assert(sizeof(rob_chara_item_cos_data) == 0x408, "\"rob_chara_item_cos_data\" struct should have a size of 0x408"); struct struc_264 { uint8_t data[0x1D8]; }; static_assert(sizeof(struc_264) == 0x1D8, "\"struc_264\" struct should have a size of 0x1D8"); struct RobSubAction { uint8_t data[0xB0]; }; static_assert(sizeof(RobSubAction) == 0xB0, "\"RobSubAction\" struct should have a size of 0xB0"); struct struc_389 { float_t frame; float_t prev_frame; float_t last_set_frame; }; static_assert(sizeof(struc_389) == 0x0C, "\"struc_389\" struct should have a size of 0x0C"); struct struc_406 { float_t frame; float_t field_4; float_t step; }; static_assert(sizeof(struc_406) == 0x0C, "\"struc_406\" struct should have a size of 0x0C"); struct rob_chara_data_hand_adjust { bool enable; int16_t scale_select; rob_chara_data_hand_adjust_type type; float_t current_scale; float_t scale; float_t duration; float_t current_time; float_t rotation_blend; float_t scale_blend; bool enable_scale; bool disable_x; bool disable_y; bool disable_z; vec3 offset; vec3 field_30; float_t arm_length; int32_t field_40; }; static_assert(sizeof(rob_chara_data_hand_adjust) == 0x44, "\"rob_chara_data_hand_adjust\" struct should have a size of 0x44"); struct rob_chara_motion { uint32_t motion_id; uint32_t prev_motion_id; struc_389 frame_data; struc_406 step_data; uint8_t data[0x1198]; rob_chara_data_hand_adjust hand_adjust[2]; rob_chara_data_hand_adjust hand_adjust_prev[2]; uint8_t data1[0x30]; }; static_assert(sizeof(rob_chara_motion) == 0x12F8, "\"rob_chara_motion\" struct should have a size of 0x12F8"); struct struc_526 { int32_t field_0; int32_t field_4; }; struct struc_228 { int32_t field_0; int32_t field_4; uint32_t field_8; int32_t field_C; }; struct struc_227 { int32_t field_0; float_t field_4; float_t field_8; }; struct struc_652 { int32_t motion_id; float_t frame_count; float_t frame; int16_t field_C; struc_228 field_10; struc_228 field_20; struc_228 field_30; struc_228 field_40; int16_t field_50; int16_t field_52; int16_t field_54; int32_t field_58; int32_t field_5C; int32_t field_60; int32_t field_64; int32_t field_68; int32_t loop_count; float_t loop_begin; float_t loop_end; float_t field_78; float_t field_7C; float_t field_80; int8_t field_84; int32_t field_88; int32_t field_8C; int32_t field_90; int16_t field_94; int16_t field_96; int16_t field_98; int32_t field_9C; int16_t field_A0; int32_t field_A4; int64_t field_A8; struc_227 field_B0[26]; int32_t field_1E8; float_t field_1EC; float_t field_1F0; float_t field_1F4; float_t field_1F8; float_t field_1FC; float_t field_200; int32_t field_204; int32_t field_208; int32_t field_20C; int64_t field_210; float_t field_218; float_t field_21C; int16_t field_220; prj::list field_228; int16_t field_238; float_t field_23C; int32_t field_240; int16_t field_244; const void* field_248; int64_t field_250; float_t field_258; int32_t field_25C; struc_526 field_260; struc_526 field_268; int32_t field_270; int16_t field_274; int16_t field_276; int32_t field_278; int32_t field_27C; int32_t field_280; int16_t field_284; int64_t field_288; int32_t field_290; int32_t field_294; int32_t field_298; float_t field_29C; int8_t field_2A0; float_t field_2A4; float_t field_2A8; float_t field_2AC; int64_t field_2B0; int16_t field_2B8; int32_t field_2BC; float_t field_2C0; float_t field_2C4; int32_t field_2C8; int32_t field_2CC; int64_t field_2D0; int64_t field_2D8; int64_t field_2E0; int16_t field_2E8; int32_t field_2EC; int32_t field_2F0; struc_526 field_2F4; int32_t field_2FC; int8_t field_300; int32_t field_304; int32_t field_308; float_t field_30C; int32_t field_310; int16_t field_314; vec3 field_318; float_t field_324; float_t field_328; int32_t iterations; }; struct struc_377 { void* current; // mothead_data void* data; // mothead_data }; struct struc_226 { int8_t field_0[27]; }; struct struc_225 { float_t field_0[27]; }; struct struc_224 { int32_t field_0[27]; }; struct struc_306 { int16_t field_0; float_t frame; float_t field_8; int16_t field_C; int16_t field_E; vec3 field_10; vec3 field_1C; vec3 field_28; int32_t field_34; int32_t field_38; int32_t field_3C; int32_t field_40; int32_t field_44; int32_t field_48; }; struct struc_651 { struc_377 field_0; int32_t field_10; int32_t field_14; int32_t field_18; float_t field_1C; vec3 field_20; struc_226 field_2C[3]; struc_225 field_80[3]; struc_224 field_1C4[3]; int64_t field_308; float_t field_310; float_t field_314; int8_t field_318; int32_t field_31C; float_t field_320; float_t field_324; float_t field_328; float_t field_32C; float_t field_330; float_t field_334; int8_t field_338; struc_306 field_33C[4]; }; struct struc_223 { struc_652 field_0; struc_651 field_330; int64_t* field_7A0; int32_t motion_set_id; }; static_assert(sizeof(struc_223) == 0x7B0, "\"struc_223\" struct should have a size of 0x7B0"); struct rob_chara_data_miku_rot { uint8_t data[0xAC]; }; static_assert(sizeof(rob_chara_data_miku_rot) == 0xAC, "\"rob_chara_data_miku_rot\" struct should have a size of 0xAC"); struct rob_chara_adjust_data { float_t scale; bool height_adjust; float_t pos_adjust_y; vec3 pos_adjust; vec3 offset; bool offset_x; bool offset_y; bool offset_z; bool get_global_trans; vec3 trans; mat4 mat; float_t left_hand_scale; float_t right_hand_scale; float_t left_hand_scale_default; float_t right_hand_scale_default; }; static_assert(sizeof(rob_chara_adjust_data) == 0x84, "\"rob_chara_adjust_data\" struct should have a size of 0x84"); struct struc_209 { uint8_t data[0x1F28]; }; static_assert(sizeof(struc_209) == 0x1F28, "\"struc_209\" struct should have a size of 0x1F28"); struct rob_chara_data { uint8_t field_0; uint8_t field_1; uint8_t field_2; uint8_t field_3; int32_t field_4; struc_264 field_8; RobSubAction rob_sub_action; rob_chara_motion motion; struc_223 field_1588; rob_chara_data_miku_rot miku_rot; rob_chara_adjust_data adjust_data; struc_209 field_1E68; float_t field_3D90; int32_t field_3D94; int16_t field_3D98; int16_t field_3D9A; int32_t field_3D9C; int32_t field_3DA0; int8_t field_3DA4; int64_t field_3DA8; int64_t field_3DB0; int32_t field_3DB8; int32_t field_3DBC; int32_t field_3DC0; int32_t field_3DC4; int32_t field_3DC8; int32_t field_3DCC; int32_t field_3DD0; float_t field_3DD4; int32_t field_3DD8; float_t field_3DDC; int8_t field_3DE0; }; static_assert(sizeof(rob_chara_data) == 0x3DE8, "\"rob_chara_data\" struct should have a size of 0x3DE8"); struct rob_chara_pv_data { uint8_t data[0xC4]; }; static_assert(sizeof(rob_chara_pv_data) == 0xC4, "\"rob_chara_pv_data\" struct should have a size of 0xC4"); struct rob_touch { uint8_t data[0x28]; }; static_assert(sizeof(rob_touch) == 0x28, "\"rob_touch\" struct should have a size of 0x28"); struct rob_chara { int8_t chara_id; int8_t field_1; int8_t field_2; int8_t field_3; int32_t type; int16_t field_8; int16_t field_A; bool field_C; bool field_D; chara_index chara_index; int32_t cos_id; int32_t field_18; float_t frame_speed; void* field_20; struct rob_chara_bone_data* bone_data; rob_chara_item_equip* item_equip; rob_chara_item_cos_data item_cos_data; rob_chara_data data; rob_chara_data data_prev; struct chara_init_data* chara_init_data; struct rob_detail* rob_detail; rob_chara_pv_data pv_data; int32_t field_80E4; rob_touch rob_touch; }; static_assert(sizeof(rob_chara) == 0x8110, "\"rob_chara\" struct should have a size of 0x8110"); struct rob_chara_item_adjust_x { mat4 mat; vec3 trans; float_t scale; rob_chara_item_adjust_x(); void reset(); }; struct rob_chara_arm_adjust_x { float_t next_value; float_t prev_value; int32_t start_frame; float_t duration; float_t scale; rob_chara_arm_adjust_x(); void reset(); }; const mat4* (FASTCALL* rob_chara_bone_data_get_mats_mat)(size_t rob_bone_data, size_t index) = (const mat4 * (FASTCALL*)(size_t rob_bone_data, size_t index))0x0000000140419520; const char* (FASTCALL* chara_index_get_auth_3d_name)(chara_index chara_index) = (const char* (FASTCALL*)(chara_index chara_index))0x0000000140508100; void(FASTCALL* sub_1405163C0)(size_t rob_chr, int32_t index, mat4* mat) = (void(FASTCALL*)(size_t rob_chr, int32_t index, mat4 * mat))0x00000001405163C0; float_t(FASTCALL* rob_chara_get_max_face_depth)(size_t rob_chr) = (float_t(FASTCALL*)(size_t rob_chr))0x0000000140516510; const mat4* (FASTCALL* rob_chara_get_bone_data_mat)(size_t rob_chr, mot_bone_index index) = (const mat4 * (FASTCALL*)(size_t rob_chr, mot_bone_index index))0x0000000140516730; const mat4* (FASTCALL* sub_140516740)(size_t rob_chr) = (const mat4 * (FASTCALL*)(size_t rob_chr))0x0000000140516740; bool(FASTCALL* rob_chara_array_check_visibility)(size_t rob_chr_smth, int32_t chara_id) = (bool(FASTCALL*)(size_t rob_chr_smth, int32_t chara_id))0x0000000140531F50; size_t(FASTCALL* get_rob_chara_smth)() = (size_t(FASTCALL*)())0x00000001405320E0; size_t(FASTCALL* rob_chara_array_get)(size_t rob_chr_smth, int32_t chara_id) = (size_t(FASTCALL*)(size_t rob_chr_smth, int32_t chara_id))0x0000000140532030; size_t(FASTCALL* rob_chara_array_get_bone_data)(size_t rob_chr_smth, int32_t chara_id) = (size_t(FASTCALL*)(size_t rob_chr_smth, int32_t chara_id))0x00000001405320F0; bool (FASTCALL* rob_chara_pv_data_array_check_chara_id)(size_t rob_chr_smth, int32_t chara_id) = (bool (FASTCALL*)(size_t rob_chr_smth, int32_t chara_id))0x00000001405327B0; static rob_chara_age_age* rob_chara_age_age_array = (rob_chara_age_age*)0x00000001411E83C0; static bool& chara_reflect = *(bool*)0x00000001411ADAFC; static bool& chara_refract = *(bool*)0x00000001411ADAFD; const mat4* rob_chara_item_equip_mat = 0; rob_chara_item_adjust_x rob_chara_item_adjust_x_array[ROB_CHARA_COUNT]; rob_chara_arm_adjust_x rob_chara_arm_adjust_x_array[ROB_CHARA_COUNT]; static void rob_chara_age_age_array_disp(int32_t chara_id, bool reflect, bool chara_color); const mat4* rob_chara_get_adjust_data_mat(size_t rob_chr) { return &((rob_chara*)rob_chr)->data.adjust_data.mat; } const mat4* rob_chara_get_item_adjust_data_mat(size_t rob_chr) { int32_t chara_id = ((rob_chara*)rob_chr)->chara_id; return &rob_chara_item_adjust_x_array[chara_id].mat; } HOOK(void, FASTCALL, sub_1405044B0, 0x00000001405044B0, rob_chara* rob_chr) { rob_chara_item_adjust_x& item_adjust = rob_chara_item_adjust_x_array[rob_chr->chara_id]; rob_chara_arm_adjust_x& arm_adjust = rob_chara_arm_adjust_x_array[rob_chr->chara_id]; if (arm_adjust.duration > 0) { float_t blend = 1.0f; if (fabsf(arm_adjust.duration) > 0.000001f) blend = (rob_chr->data.motion.frame_data.frame - (float_t)arm_adjust.start_frame) / arm_adjust.duration; blend = clamp_def(blend, 0.0f, 1.0f); if (fabsf(blend - 1.0f) <= 0.000001f) arm_adjust.duration = -1.0f; arm_adjust.scale = lerp_def(arm_adjust.prev_value, arm_adjust.next_value, blend); static float_t(FASTCALL * chara_size_table_get_value)(uint32_t id) = (float_t(FASTCALL*)(uint32_t id))0x00000001405103C0; float_t default_scale = chara_size_table_get_value(1); item_adjust.scale = default_scale + (rob_chr->data.adjust_data.scale - default_scale) * arm_adjust.scale; } originalsub_1405044B0(rob_chr); } static void rob_chara_data_adjuct_set_trans(rob_chara_adjust_data* rob_chr_adj, rob_chara_item_adjust_x* rob_chr_itm_adj_x, vec3& trans, bool pos_adjust, vec3* global_trans) { float_t scale = rob_chr_adj->scale; float_t item_scale = rob_chr_itm_adj_x->scale; vec3 _offset = rob_chr_adj->offset; if (global_trans) _offset.y += global_trans->y; vec3 _trans = trans; vec3 _item_trans = trans; if (rob_chr_adj->height_adjust) { _trans.y += rob_chr_adj->pos_adjust_y; _item_trans.y += rob_chr_adj->pos_adjust_y; } else { vec3 temp = (_trans - _offset) * scale + _offset; vec3 arm_temp = (_item_trans - _offset) * item_scale + _offset; if (!rob_chr_adj->offset_x) { _trans.x = temp.x; _item_trans.x = arm_temp.x; } if (!rob_chr_adj->offset_y) { _trans.y = temp.y; _item_trans.y = arm_temp.y; } if (!rob_chr_adj->offset_z) { _trans.z = temp.z; _item_trans.z = arm_temp.z; } } if (pos_adjust) { _trans = rob_chr_adj->pos_adjust + _trans; _item_trans = rob_chr_adj->pos_adjust + _item_trans; } rob_chr_adj->trans = _trans - trans * scale; rob_chr_itm_adj_x->trans = _item_trans - trans * item_scale; } HOOK(void, FASTCALL, rob_chara_set_data_adjust_mat, 0x00000001405050D0, rob_chara* rob_chr, rob_chara_adjust_data* rob_chr_adj, bool pos_adjust) { mat4 mat = *rob_chara_bone_data_get_mats_mat((size_t)rob_chr->bone_data, ROB_BONE_N_HARA_CP); vec3 trans; mat4_transpose(&mat, &mat); mat4_get_translation(&mat, &trans); rob_chara_item_adjust_x* item_adjust = &rob_chara_item_adjust_x_array[rob_chr->chara_id]; vec3* global_trans = 0; if (rob_chr_adj->get_global_trans) { static vec3* (FASTCALL * rob_chara_bone_data_get_global_trans)(size_t rob_bone_data) = (vec3 * (FASTCALL*)(size_t rob_bone_data))0x0000000140419360; global_trans = rob_chara_bone_data_get_global_trans((size_t)rob_chr->bone_data); } rob_chara_data_adjuct_set_trans(rob_chr_adj, item_adjust, trans, pos_adjust, global_trans); float_t scale = rob_chr_adj->scale; mat4_scale(scale, scale, scale, &rob_chr_adj->mat); mat4_set_translation(&rob_chr_adj->mat, &rob_chr_adj->trans); mat4_transpose(&rob_chr_adj->mat, &rob_chr_adj->mat); float_t item_scale = item_adjust->scale; mat4_scale(item_scale, item_scale, item_scale, &item_adjust->mat); mat4_set_translation(&item_adjust->mat, &item_adjust->trans); mat4_transpose(&item_adjust->mat, &item_adjust->mat); } HOOK(void, FASTCALL, rob_chara_reset_data, 0x0000000140507210, rob_chara* rob_chr, rob_chara_pv_data* pv_data) { rob_chara_item_adjust_x& item_adjust = rob_chara_item_adjust_x_array[rob_chr->chara_id]; rob_chara_arm_adjust_x& arm_adjust = rob_chara_arm_adjust_x_array[rob_chr->chara_id]; item_adjust.reset(); arm_adjust.reset(); originalrob_chara_reset_data(rob_chr, pv_data); item_adjust.scale = rob_chr->data.adjust_data.scale; } static void sub_140512C20(rob_chara_item_equip* rob_itm_equip) { if (rob_itm_equip->field_D0.is_null() || rob_itm_equip->field_D4 == -1) return; mat4 mat = mat4_identity; const char* name; if (rob_itm_equip->field_DC == 1) { name = "kl_te_r_wj"; mat4_translate(0.0f, 0.0f, 0.082f, &mat); mat4_mul_rotate_zyx(&mat, (float_t)(-90.9 * DEG_TO_RAD), 0.0f, (float_t)(-179.5 * DEG_TO_RAD), &mat); } if (rob_itm_equip->field_DC == 2) { name = "kl_te_l_wj"; mat4_translate(0.0f, 0.0015f, -0.0812f, &mat); mat4_mul_rotate_zyx(&mat, (float_t)(-34.5 * DEG_TO_RAD), 0.0f, (float_t)(-179.5 * DEG_TO_RAD), &mat); } else name = "j_1_hyoutan_000wj"; bone_node* node = rob_itm_equip->item_equip_object[rob_itm_equip->field_D4].get_bone_node(name); if (!node || !node->mat) return; mat4_transpose(&mat, &mat); mat4_mul(&mat, node->mat, &mat); int32_t tex_pat_count = (int32_t)rob_itm_equip->texture_pattern.size(); if (tex_pat_count) disp_manager->set_texture_pattern(tex_pat_count, rob_itm_equip->texture_pattern.data()); disp_manager->entry_obj_by_object_info(&mat, rob_itm_equip->field_D0); if (tex_pat_count) disp_manager->set_texture_pattern(); } static float_t sub_140512F60(rob_chara_item_equip* rob_itm_equip) { mat4* mats = rob_itm_equip->matrices; float_t y = 1.0f; y = min_def(y, mats[ 0].row1.w); y = min_def(y, mats[175].row1.w); y = min_def(y, mats[181].row1.w); y = min_def(y, mats[105].row1.w); y = min_def(y, mats[140].row1.w); return y; } HOOK(void, FASTCALL, rob_chara_item_equip_disp, 0x0000000140512950, rob_chara_item_equip* rob_item_equip, int32_t chara_id) { mdl::ObjFlags flags = (mdl::ObjFlags)0; if (chara_reflect) enum_or(flags, mdl::OBJ_CHARA_REFLECT); if (chara_refract) enum_or(flags, mdl::OBJ_REFRACT); mdl::DispManager& disp_manager = *::disp_manager; if (rob_item_equip->shadow_type != -1) { if (rob_item_equip->field_A0 & 0x04) { vec3 pos = rob_item_equip->position; pos.y -= 0.2f; shadow_ptr_get()->field_1D0[rob_item_equip->shadow_type].push_back(pos); float_t v9; if (sub_140512F60(rob_item_equip) <= -0.2f) v9 = -0.5f; else v9 = 0.05f; shadow_ptr_get()->field_1C0[rob_item_equip->shadow_type] = v9; disp_manager.set_shadow_type(rob_item_equip->shadow_type); enum_or(flags, mdl::OBJ_SHADOW); } if (rob_item_equip->field_A0 & 0x01) enum_or(flags, mdl::OBJ_4); } disp_manager.set_obj_flags(flags); disp_manager.set_chara_color(rob_item_equip->chara_color); vec4 temp_texture_color_coeff; disp_manager.get_texture_color_coeff(temp_texture_color_coeff); disp_manager.set_texture_color_coefficients(rob_item_equip->texture_color_coefficients); disp_manager.set_wet_param(rob_item_equip->wet); render_manager->field_31C |= rob_item_equip->npr_flag; sub_140512C20(rob_item_equip); rob_chara_age_age_array_disp(chara_id, chara_reflect, rob_item_equip->chara_color); if (rob_item_equip->item_equip_range) for (int32_t i = rob_item_equip->first_item_equip_object; i < rob_item_equip->max_item_equip_object; i++) rob_item_equip->item_equip_object[i].disp(&rob_item_equip->mat); else { for (int32_t i = ITEM_ATAMA; i < ITEM_MAX; i++) { mdl::ObjFlags chara_flags = (mdl::ObjFlags)0; if (!rob_item_equip->field_18[i]) { if (chara_reflect) enum_or(chara_flags, mdl::OBJ_CHARA_REFLECT); if (chara_refract) enum_or(chara_flags, mdl::OBJ_REFRACT); } mdl::ObjFlags flags = (mdl::ObjFlags)(mdl::OBJ_4 | mdl::OBJ_SHADOW); if (i == ITEM_HARA) flags = (mdl::ObjFlags)0; if (!(rob_item_equip->field_A0 & 0x04)) enum_and(flags, ~mdl::OBJ_SHADOW); disp_manager.set_obj_flags((mdl::ObjFlags)(chara_flags | flags | mdl::OBJ_SSS)); rob_item_equip->item_equip_object[i].disp(&rob_item_equip->mat); } } disp_manager.set_texture_color_coefficients(temp_texture_color_coeff); disp_manager.set_wet_param(); disp_manager.set_chara_color(); disp_manager.set_obj_flags(); disp_manager.set_shadow_type(); } HOOK(void, FASTCALL, rob_chara_set_chara_size, 0x0000000140516810, rob_chara* rob_chr, float_t value) { originalrob_chara_set_chara_size(rob_chr, value); rob_chara_item_adjust_x& item_adjust = rob_chara_item_adjust_x_array[rob_chr->chara_id]; item_adjust.scale = value; } HOOK(void, FASTCALL, sub_1405335C0, 0x0000001405335C0, struc_223* a1) { originalsub_1405335C0(a1); int32_t chara_id = ((rob_chara*)((size_t)a1 - 0x19C8))->chara_id; rob_chara_arm_adjust_x_array[chara_id].reset(); } HOOK(void, FASTCALL, mothead_func_32, 0x0000000140533C00, struct mothead_func_data* func_data, void* data, const struct mothead_data* mhd_data, int64_t frame) { float_t v8 = (float_t)((int16_t*)data)[0]; int32_t v5 = ((int32_t*)data)[1]; float_t v9 = ((float_t*)data)[2]; int32_t v10 = ((int32_t*)data)[3]; if (v8 != (int16_t)0xFA0C || v10 != 0xD62721C5) { // X originalmothead_func_32(func_data, data, mhd_data, frame); return; } size_t rob_chr_data = *(size_t*)((size_t)func_data + 0x08); rob_chara* rob_chr = ((rob_chara*)((size_t)rob_chr_data - 0x440)); float_t value = v9; float_t duration = (float_t)v5; rob_chara_arm_adjust_x& arm_adjust = rob_chara_arm_adjust_x_array[rob_chr->chara_id]; arm_adjust.next_value = value; arm_adjust.prev_value = arm_adjust.scale; arm_adjust.start_frame = (int32_t)frame; arm_adjust.duration = max_def(duration, 0.0f); return; } HOOK(bool, FASTCALL, sub_14053ACA0, 0x000000014053ACA0, rob_chara* rob_chr, int32_t hand) { if (hand >= 2 || !rob_chr->data.motion.hand_adjust[hand].enable) return false; rob_chara_item_adjust_x& item_adjust = rob_chara_item_adjust_x_array[rob_chr->chara_id]; rob_chara_item_adjust_x item_adjust_temp = item_adjust; float_t chara_scale = rob_chr->data.adjust_data.scale; float_t adjust_scale = rob_chr->data.motion.hand_adjust[hand].current_scale; item_adjust.scale = adjust_scale / chara_scale; originalsub_14053ACA0(rob_chr, hand); item_adjust = item_adjust_temp; return true; } HOOK(void, FASTCALL, rob_chara_set_hand_adjust, 0x000000014053C070, rob_chara* rob_chr, rob_chara_data_hand_adjust* adjust, rob_chara_data_hand_adjust* prev_adjust) { if (!adjust->enable) return; static float_t(FASTCALL * chara_size_table_get_value)(uint32_t id) = (float_t(FASTCALL*)(uint32_t id))0x00000001405103C0; static float_t(FASTCALL * rob_chara_array_get_data_adjust_scale)(size_t rob_chr_smth, int32_t chara_id) = (float_t(FASTCALL*)(size_t rob_chr_smth, int32_t chara_id))0x0000000140531F90; float_t chara_scale = rob_chr->data.adjust_data.scale; float_t opposite_chara_scale = rob_chara_array_get_data_adjust_scale(get_rob_chara_smth(), rob_chr->chara_id ? 0 : 1); bool chara_opposite_chara_same = fabsf(chara_scale - opposite_chara_scale) <= 0.000001f; switch (adjust->type) { case ROB_CHARA_DATA_HAND_ADJUST_NORMAL: adjust->scale = chara_size_table_get_value(1); break; case ROB_CHARA_DATA_HAND_ADJUST_SHORT: adjust->scale = chara_size_table_get_value(2); break; case ROB_CHARA_DATA_HAND_ADJUST_TALL: adjust->scale = chara_size_table_get_value(0); break; case ROB_CHARA_DATA_HAND_ADJUST_MIN: adjust->scale = min_def(opposite_chara_scale, chara_scale); break; case ROB_CHARA_DATA_HAND_ADJUST_MAX: adjust->scale = max_def(opposite_chara_scale, chara_scale); break; case ROB_CHARA_DATA_HAND_ADJUST_OPPOSITE_CHARA: adjust->scale = opposite_chara_scale; break; case ROB_CHARA_DATA_HAND_ADJUST_1P: adjust->scale = rob_chara_array_get_data_adjust_scale(get_rob_chara_smth(), 0); break; case ROB_CHARA_DATA_HAND_ADJUST_2P: adjust->scale = rob_chara_array_get_data_adjust_scale(get_rob_chara_smth(), 1); break; case ROB_CHARA_DATA_HAND_ADJUST_3P: adjust->scale = rob_chara_array_get_data_adjust_scale(get_rob_chara_smth(), 2); break; case ROB_CHARA_DATA_HAND_ADJUST_4P: adjust->scale = rob_chara_array_get_data_adjust_scale(get_rob_chara_smth(), 3); break; case ROB_CHARA_DATA_HAND_ADJUST_ITEM: // X adjust->scale = rob_chara_item_adjust_x_array[rob_chr->chara_id].scale; break; } if (adjust->scale_select == 1 && adjust->enable_scale && chara_opposite_chara_same) { adjust->scale_select = 0; adjust->rotation_blend = prev_adjust->rotation_blend; adjust->disable_x = prev_adjust->disable_x; adjust->disable_y = prev_adjust->disable_y; adjust->disable_z = prev_adjust->disable_z; adjust->scale_blend = 1.0f; } float_t prev_scale; if (prev_adjust->enable || prev_adjust->scale_select == 1) prev_scale = prev_adjust->current_scale; else prev_scale = chara_scale; float_t scale; if (adjust->scale_select == 1) scale = adjust->scale; else scale = chara_scale; if (fabsf(prev_scale - scale * adjust->scale_blend) <= 0.000001f || adjust->duration <= adjust->current_time || fabsf(adjust->duration - adjust->current_time) <= 0.000001f) { adjust->current_scale = lerp_def(prev_scale, scale, adjust->scale_blend); if (fabsf(adjust->current_scale - chara_scale) <= 0.000001f && adjust->type != ROB_CHARA_DATA_HAND_ADJUST_ITEM) { adjust->current_scale = chara_scale; adjust->enable = false; } } else { float_t t = (adjust->current_time + 1.0f) / (adjust->duration + 1.0f); adjust->current_scale = lerp_def(prev_scale, scale, t * adjust->scale_blend); adjust->current_time += rob_chr->data.motion.step_data.frame; } } void rob_patch() { INSTALL_HOOK(rob_chara_set_data_adjust_mat); INSTALL_HOOK(rob_chara_reset_data); INSTALL_HOOK(sub_1405044B0); INSTALL_HOOK(rob_chara_item_equip_disp); INSTALL_HOOK(rob_chara_set_chara_size); INSTALL_HOOK(sub_1405335C0); INSTALL_HOOK(mothead_func_32); INSTALL_HOOK(sub_14053ACA0); INSTALL_HOOK(rob_chara_set_hand_adjust); } void rob_chara_age_age_object::disp(size_t chara_index, bool npr, bool reflect, const vec3& a5, bool chara_color) { int32_t disp_count = this->disp_count; if (!objset_info || !disp_count) return; disp_count = min_def(disp_count, 10); std::pair v44[10]; for (int32_t i = 0; i < disp_count; i++) { v44[i].first = vec3::dot(trans[i], a5); v44[i].second = i; } if (disp_count >= 2) std::sort(v44, v44 + disp_count, [](const std::pair& a, const std::pair& b) { return a.first < b.first; }); obj_vert_buf.cycle_index(); GLArrayBuffer buffer = obj_vert_buf.get_buffer(); size_t vtx_data = (size_t)buffer.MapMemory(); if (!vtx_data) return; size_t vertex_array_size = this->vertex_array_size; for (int32_t i = 0; i < disp_count; i++) memmove((void*)(vtx_data + vertex_array_size * i), (void*)((size_t)vertex_data + vertex_array_size * v44[i].second), vertex_array_size); buffer.UnmapMemory(); mesh.num_vertex = disp_count * num_vertex; sub_mesh.num_index = disp_count * num_index; sub_mesh.material_index = npr ? 1 : 0; mdl::ObjFlags flags = (mdl::ObjFlags)(mdl::OBJ_SSS | mdl::OBJ_4 | mdl::OBJ_SHADOW); if (reflect) enum_or(flags, mdl::OBJ_CHARA_REFLECT); disp_manager->set_obj_flags(flags); disp_manager->set_chara_color(chara_color); disp_manager->set_shadow_type(chara_index ? SHADOW_STAGE : SHADOW_CHARA); static prj::vector* (FASTCALL * rob_chara_age_age_object__get_obj_set_texture)(rob_chara_age_age_object * rob_age_age_obj) = (prj::vector*(FASTCALL*)(rob_chara_age_age_object * rob_age_age_obj))0x000000014045A8E0; disp_manager->entry_obj_by_obj(&mat4_identity, &obj, rob_chara_age_age_object__get_obj_set_texture(this), &obj_vert_buf, &obj_index_buf, 0, 1.0f); } void rob_chara_age_age::disp(size_t chara_id, bool npr, bool reflect, const vec3& a5, bool chara_color) { if (alpha >= 0.1f && this->visible) object.disp(chara_id, npr || this->npr, reflect, a5, chara_color); } void rob_chara_item_equip_object::disp(const mat4* mat) { if (obj_info.is_null()) return; mdl::ObjFlags flags = disp_manager->get_obj_flags(); mdl::ObjFlags chara_flags = flags; if (fabsf(alpha - 1.0f) > 0.000001f) enum_or(chara_flags, obj_flags); else enum_and(chara_flags, ~(mdl::OBJ_ALPHA_ORDER_3 | mdl::OBJ_ALPHA_ORDER_2 | mdl::OBJ_ALPHA_ORDER_1)); disp_manager->set_obj_flags(chara_flags); if (can_disp) { disp_manager->entry_obj_by_object_info_object_skin(obj_info, &texture_pattern, &texture_data, alpha, mats, ex_data_bone_mats.data(), 0, mat); rob_chara_item_equip_mat = mat; for (ExNodeBlock*& i : node_blocks) i->__vftable->Disp(i); } disp_manager->set_obj_flags(flags); } int32_t rob_chara_item_equip_object::get_bone_index(const char* name) { int32_t(FASTCALL * sub_1401F13B0)(int32_t a1, const char* a2) = (int32_t(FASTCALL*)(int32_t a1, const char* a2))0x00000001401F13B0; int32_t bone_index = sub_1401F13B0(0, name); if (bone_index == -1) for (auto& i : ex_bones) if (!str_utils_compare(name, i.first)) return 0x8000 | i.second; return bone_index; } bone_node* rob_chara_item_equip_object::get_bone_node( int32_t bone_index) { if (!(bone_index & 0x8000)) return &bone_nodes[bone_index & 0x7FFF]; else if ((bone_index & 0x7FFF) < ex_data_bone_nodes.size()) return &ex_data_bone_nodes[bone_index & 0x7FFF]; return 0; } bone_node* rob_chara_item_equip_object::get_bone_node(const char* name) { return get_bone_node(get_bone_index(name)); } rob_chara_item_adjust_x::rob_chara_item_adjust_x() : scale() { reset(); } void rob_chara_item_adjust_x::reset() { mat4_translate(&trans, &mat); mat4_transpose(&mat, &mat); scale = 1.0f; } rob_chara_arm_adjust_x::rob_chara_arm_adjust_x() : next_value(), prev_value(), start_frame(), duration(), scale() { reset(); } void rob_chara_arm_adjust_x::reset() { next_value = 0.0f; prev_value = 0.0f; start_frame = -1; duration = -1.0f; scale = 1.0f; } static void rob_chara_age_age_disp(rob_chara_age_age* arr, int32_t chara_id, bool reflect, bool chara_color) { bool npr = !!render_manager->npr_param; mat4& view = camera_data->view; vec3 v11 = *(vec3*)&view.row2; arr[chara_id * 3 + 0].disp(chara_id, npr, reflect, v11, chara_color); arr[chara_id * 3 + 1].disp(chara_id, npr, reflect, v11, chara_color); arr[chara_id * 3 + 2].disp(chara_id, npr, reflect, v11, chara_color); } static void rob_chara_age_age_array_disp(int32_t chara_id, bool reflect, bool chara_color) { mdl::ObjFlags obj_flags = disp_manager->get_obj_flags(); rob_chara_age_age_disp(rob_chara_age_age_array, chara_id, reflect, chara_color); disp_manager->set_obj_flags(obj_flags); }