diff --git a/source/acmd_wrapper.hpp b/source/acmd_wrapper.hpp index 69fcb01..6dc062f 100644 --- a/source/acmd_wrapper.hpp +++ b/source/acmd_wrapper.hpp @@ -3,10 +3,10 @@ #include <switch.h> -#include "imports/app/sv_animcmd.hpp" -#include "imports/app/sv_system.hpp" -#include "imports/app/sv_math.hpp" #include "imports/app/lua_bind.hpp" +#include "imports/app/sv_animcmd.hpp" +#include "imports/app/sv_math.hpp" +#include "imports/app/sv_system.hpp" #include "imports/lib/l2c.hpp" #include <initializer_list> @@ -14,71 +14,71 @@ using namespace lib; u64 load_module(u64 module_accessor, u64 module_offset) { - return LOAD64(module_accessor + module_offset); + return LOAD64(module_accessor + module_offset); } void* load_module_impl(u64 module, u64 function_offset) { - u64 function_impl = LOAD64(module) + function_offset; - return (void*) LOAD64(function_impl); + u64 function_impl = LOAD64(module) + function_offset; + return (void*)LOAD64(function_impl); } bool is_before_frame(u64 lua_state, float f) { - u64 acmd_frame_obj = LOAD64(LOAD64(lua_state - 8) + 432LL); - return *(float*)((*((u32 *)acmd_frame_obj + 64) + 15) & 0xFFFFFFF0) < f; + u64 acmd_frame_obj = LOAD64(LOAD64(lua_state - 8) + 432LL); + return *(float*)((*((u32*)acmd_frame_obj + 64) + 15) & 0xFFFFFFF0) < f; } struct ACMD { - L2CAgent* l2c_agent; - u64 module_accessor; + L2CAgent* l2c_agent; + u64 module_accessor; - ACMD(L2CAgent* agent) { - l2c_agent = agent; - module_accessor = app::sv_system::battle_object_module_accessor(l2c_agent->lua_state_agent); - } + ACMD(L2CAgent* agent) { + l2c_agent = agent; + module_accessor = app::sv_system::battle_object_module_accessor( + l2c_agent->lua_state_agent); + } - void frame(float f) { - l2c_agent->clear_lua_stack(); - L2CValue frame_val(f); - l2c_agent->push_lua_stack(&frame_val); - app::sv_animcmd::frame(l2c_agent->lua_state_agent, f); - l2c_agent->clear_lua_stack(); - } + void frame(float f) { + l2c_agent->clear_lua_stack(); + L2CValue frame_val(f); + l2c_agent->push_lua_stack(&frame_val); + app::sv_animcmd::frame(l2c_agent->lua_state_agent, f); + l2c_agent->clear_lua_stack(); + } - // attempted reimplementation of sv_animcmd::frame - bool _frame(float f) { + // attempted reimplementation of sv_animcmd::frame + bool _frame(float f) { u64 acmd_obj = LOAD64(LOAD64(l2c_agent->lua_state_agent - 8) + 432); - if ( !is_before_frame(l2c_agent->lua_state_agent, f) ) - return true; - + if (!is_before_frame(l2c_agent->lua_state_agent, f)) return true; + *(u8*)(acmd_obj + 47) = 3; LOAD64(acmd_obj + 48) = (u64)&is_before_frame; *(float*)(acmd_obj + 56) = f; - + u64 acmd_obj_other = LOAD64(acmd_obj); if (*(u8*)(acmd_obj_other + 664)) { - void (*some_func)(u64) = (void (*)(u64)) LOAD64(LOAD64(LOAD64(acmd_obj_other + 656)) + 16); + void (*some_func)(u64) = (void (*)(u64))LOAD64( + LOAD64(LOAD64(acmd_obj_other + 656)) + 16); some_func(LOAD64(acmd_obj_other + 656)); return true; } bool doThing = false; - if ( !*(u16*)(l2c_agent->lua_state_agent + 196)) { + if (!*(u16*)(l2c_agent->lua_state_agent + 196)) { u64 v4 = LOAD64(l2c_agent->lua_state_agent + 32); *(u8*)(l2c_agent->lua_state_agent + 12) = 1; - LOAD64(v4 + 56) = LOAD64(v4) - LOAD64(l2c_agent->lua_state_agent + 56); - if ( *(u8*)(v4 + 66) & 2) - return true; + LOAD64(v4 + 56) = + LOAD64(v4) - LOAD64(l2c_agent->lua_state_agent + 56); + if (*(u8*)(v4 + 66) & 2) return true; doThing = true; } - - if ( doThing || LOAD64(LOAD64(l2c_agent->lua_state_agent + 24) + 200) == l2c_agent->lua_state_agent) { - // throw + if (doThing || LOAD64(LOAD64(l2c_agent->lua_state_agent + 24) + 200) == + l2c_agent->lua_state_agent) { + // throw u64 v4 = LOAD64(l2c_agent->lua_state_agent + 32); LOAD64(v4 + 32) = 0; LOAD64(v4) = LOAD64(l2c_agent->lua_state_agent + 16) - 16; - } return false; @@ -86,132 +86,130 @@ struct ACMD { // throw } - void wait(float f) { - l2c_agent->clear_lua_stack(); - L2CValue frame_val(f); - l2c_agent->push_lua_stack(&frame_val); - app::sv_animcmd::wait(l2c_agent->lua_state_agent, f); - l2c_agent->clear_lua_stack(); - } + void wait(float f) { + l2c_agent->clear_lua_stack(); + L2CValue frame_val(f); + l2c_agent->push_lua_stack(&frame_val); + app::sv_animcmd::wait(l2c_agent->lua_state_agent, f); + l2c_agent->clear_lua_stack(); + } - bool is_excute() { - l2c_agent->clear_lua_stack(); - app::sv_animcmd::is_excute(l2c_agent->lua_state_agent); - L2CValue is_excute; - l2c_agent->get_lua_stack(1, &is_excute); - bool excute = (bool)(is_excute); - l2c_agent->clear_lua_stack(); - return excute; - } + bool is_excute() { + l2c_agent->clear_lua_stack(); + app::sv_animcmd::is_excute(l2c_agent->lua_state_agent); + L2CValue is_excute; + l2c_agent->get_lua_stack(1, &is_excute); + bool excute = (bool)(is_excute); + l2c_agent->clear_lua_stack(); + return excute; + } - void wrap(u64 (*acmd_func)(u64), std::initializer_list<L2CValue> list) { - l2c_agent->clear_lua_stack(); - for (L2CValue elem : list) - l2c_agent->push_lua_stack(&elem); + void wrap(u64 (*acmd_func)(u64), std::initializer_list<L2CValue> list) { + l2c_agent->clear_lua_stack(); + for (L2CValue elem : list) l2c_agent->push_lua_stack(&elem); - acmd_func(l2c_agent->lua_state_agent); - l2c_agent->clear_lua_stack(); - } + acmd_func(l2c_agent->lua_state_agent); + l2c_agent->clear_lua_stack(); + } - void ATTACK( - u64 i1, // ID - u64 i2, // Part - u64 h1, // Bone - float f1, // Damage - u64 i3, // Angle - u64 i4, // KBG - u64 i5, // FKB - u64 i6, // BKB - float f2, // Size - float f3, // X - float f4, // Y - float f5, // Z - // X2 - // Y2 - // Z2 - float f6, // Hitlag - float f7, // SDI - u64 i7, // Clang/Rebound - u64 i8, // Facing Restriction - u64 i9, // Fixed Weight - u64 i10, // Shield Damage - float f8, // Trip Chance - u64 i11, // Rehite Rate - u64 i12, // Reflectable - u64 i13, // Absorbable - u64 i14, // Flinchless - u64 i15, // Disable Hitlag - u64 i16, // Direct - u64 i17, // Ground/Air - u64 i18, // Hit Bits - u64 i19, // Collision Bits - u64 i20, // Friendly Fire - u64 h2, // Effect - u64 i21, // SFX Level - u64 i22, // SFX Type - u64 i23) { // Move Type - wrap(app::sv_animcmd::ATTACK, { - L2CValue(i1), L2CValue(i2), L2CValue(h1), L2CValue(f1), - L2CValue(i3), L2CValue(i4), L2CValue(i5), L2CValue(i6), - L2CValue(f2), L2CValue(f3), L2CValue(f4), L2CValue(f5), - L2CValue("void"), L2CValue("void"), L2CValue("void"), L2CValue(f6), - L2CValue(f7), L2CValue(i7), L2CValue(i8), L2CValue(i9), - L2CValue(i10), L2CValue(f8), L2CValue(i11), L2CValue(i12), - L2CValue(i13), L2CValue(i14), L2CValue(i15), L2CValue(i16), - L2CValue(i17), L2CValue(i18), L2CValue(i19), L2CValue(i20), - L2CValue(h2), L2CValue(i21), L2CValue(i22), L2CValue(i23) - }); - } + void ATTACK(u64 i1, // ID + u64 i2, // Part + u64 h1, // Bone + float f1, // Damage + u64 i3, // Angle + u64 i4, // KBG + u64 i5, // FKB + u64 i6, // BKB + float f2, // Size + float f3, // X + float f4, // Y + float f5, // Z + // X2 + // Y2 + // Z2 + float f6, // Hitlag + float f7, // SDI + u64 i7, // Clang/Rebound + u64 i8, // Facing Restriction + u64 i9, // Fixed Weight + u64 i10, // Shield Damage + float f8, // Trip Chance + u64 i11, // Rehite Rate + u64 i12, // Reflectable + u64 i13, // Absorbable + u64 i14, // Flinchless + u64 i15, // Disable Hitlag + u64 i16, // Direct + u64 i17, // Ground/Air + u64 i18, // Hit Bits + u64 i19, // Collision Bits + u64 i20, // Friendly Fire + u64 h2, // Effect + u64 i21, // SFX Level + u64 i22, // SFX Type + u64 i23) { // Move Type + wrap(app::sv_animcmd::ATTACK, + {L2CValue(i1), L2CValue(i2), L2CValue(h1), + L2CValue(f1), L2CValue(i3), L2CValue(i4), + L2CValue(i5), L2CValue(i6), L2CValue(f2), + L2CValue(f3), L2CValue(f4), L2CValue(f5), + L2CValue("void"), L2CValue("void"), L2CValue("void"), + L2CValue(f6), L2CValue(f7), L2CValue(i7), + L2CValue(i8), L2CValue(i9), L2CValue(i10), + L2CValue(f8), L2CValue(i11), L2CValue(i12), + L2CValue(i13), L2CValue(i14), L2CValue(i15), + L2CValue(i16), L2CValue(i17), L2CValue(i18), + L2CValue(i19), L2CValue(i20), L2CValue(h2), + L2CValue(i21), L2CValue(i22), L2CValue(i23)}); + } - void ATTACK( - u64 i1, // ID - u64 i2, // Part - u64 h1, // Bone - float f1, // Damage - u64 i3, // Angle - u64 i4, // KBG - u64 i5, // FKB - u64 i6, // BKB - float f2, // Size - float f3, // X - float f4, // Y - float f5, // Z - float fX2, // X2 - float fY2, // Y2 - float fZ2, // Z2 - float f6, // Hitlag - float f7, // SDI - u64 i7, // Clang/Rebound - u64 i8, // Facing Restriction - u64 i9, // Fixed Weight - u64 i10, // Shield Damage - float f8, // Trip Chance - u64 i11, // Rehite Rate - u64 i12, // Reflectable - u64 i13, // Absorbable - u64 i14, // Flinchless - u64 i15, // Disable Hitlag - u64 i16, // Direct - u64 i17, // Ground/Air - u64 i18, // Hit Bits - u64 i19, // Collision Bits - u64 i20, // Friendly Fire - u64 h2, // Effect - u64 i21, // SFX Level - u64 i22, // SFX Type - u64 i23) { // Move Type - wrap(app::sv_animcmd::ATTACK, { - L2CValue(i1), L2CValue(i2), L2CValue(h1), L2CValue(f1), - L2CValue(i3), L2CValue(i4), L2CValue(i5), L2CValue(i6), - L2CValue(f2), L2CValue(f3), L2CValue(f4), L2CValue(f5), - L2CValue(fX2), L2CValue(fY2), L2CValue(fZ2), L2CValue(f6), - L2CValue(f7), L2CValue(i7), L2CValue(i8), L2CValue(i9), - L2CValue(i10), L2CValue(f8), L2CValue(i11), L2CValue(i12), - L2CValue(i13), L2CValue(i14), L2CValue(i15), L2CValue(i16), - L2CValue(i17), L2CValue(i18), L2CValue(i19), L2CValue(i20), - L2CValue(h2), L2CValue(i21), L2CValue(i22), L2CValue(i23) - }); - } + void ATTACK(u64 i1, // ID + u64 i2, // Part + u64 h1, // Bone + float f1, // Damage + u64 i3, // Angle + u64 i4, // KBG + u64 i5, // FKB + u64 i6, // BKB + float f2, // Size + float f3, // X + float f4, // Y + float f5, // Z + float fX2, // X2 + float fY2, // Y2 + float fZ2, // Z2 + float f6, // Hitlag + float f7, // SDI + u64 i7, // Clang/Rebound + u64 i8, // Facing Restriction + u64 i9, // Fixed Weight + u64 i10, // Shield Damage + float f8, // Trip Chance + u64 i11, // Rehite Rate + u64 i12, // Reflectable + u64 i13, // Absorbable + u64 i14, // Flinchless + u64 i15, // Disable Hitlag + u64 i16, // Direct + u64 i17, // Ground/Air + u64 i18, // Hit Bits + u64 i19, // Collision Bits + u64 i20, // Friendly Fire + u64 h2, // Effect + u64 i21, // SFX Level + u64 i22, // SFX Type + u64 i23) { // Move Type + wrap(app::sv_animcmd::ATTACK, + {L2CValue(i1), L2CValue(i2), L2CValue(h1), L2CValue(f1), + L2CValue(i3), L2CValue(i4), L2CValue(i5), L2CValue(i6), + L2CValue(f2), L2CValue(f3), L2CValue(f4), L2CValue(f5), + L2CValue(fX2), L2CValue(fY2), L2CValue(fZ2), L2CValue(f6), + L2CValue(f7), L2CValue(i7), L2CValue(i8), L2CValue(i9), + L2CValue(i10), L2CValue(f8), L2CValue(i11), L2CValue(i12), + L2CValue(i13), L2CValue(i14), L2CValue(i15), L2CValue(i16), + L2CValue(i17), L2CValue(i18), L2CValue(i19), L2CValue(i20), + L2CValue(h2), L2CValue(i21), L2CValue(i22), L2CValue(i23)}); + } }; -#endif // ACMD_WRAPPER_H +#endif // ACMD_WRAPPER_H diff --git a/source/hitbox_visualizer.hpp b/source/hitbox_visualizer.hpp index 3c579ea..3feba09 100644 --- a/source/hitbox_visualizer.hpp +++ b/source/hitbox_visualizer.hpp @@ -6,11 +6,11 @@ #include "useful/useful.h" #include "useful/visual.h" -#include "imports/lib/l2c.hpp" #include "acmd_wrapper.hpp" +#include "imports/lib/l2c.hpp" #include "saltysd/saltysd_helper.hpp" -#include "useful/const_value_table.h" #include "taunt_toggles.h" +#include "useful/const_value_table.h" #include "useful/raygun_printer.hpp" @@ -23,273 +23,286 @@ u64 effect_manager_addr; void (*AttackModule_set_attack_lua_state)(u64, u64); u64 Catch_jumpback; -Vector3f ID_COLORS[8] = { // used to tint the hitbox effects -- make sure that at least one component is equal to 1.0 - { 1.0f, 0.0f, 0.0f }, // #ff0000 (red) - { 1.0f, 0.4f, 0.0f }, // #ff9900 (orange) - { 0.8f, 1.0f, 0.0f }, // #ccff00 (yellow) - { 0.2f, 1.0f, 0.2f }, // #00ff33 (green) - { 0.0f, 0.8f, 1.0f }, // #00ccff (sky blue) - { 0.4f, 0.4f, 1.0f }, // #6666ff (blue) - { 0.8f, 0.0f, 1.0f }, // #cc00ff (purple) - { 1.0f, 0.2f, 0.8f }, // #ff33cc (pink) +Vector3f ID_COLORS[8] = { + // used to tint the hitbox effects -- make sure that at least one component + // is equal to 1.0 + {1.0f, 0.0f, 0.0f}, // #ff0000 (red) + {1.0f, 0.4f, 0.0f}, // #ff9900 (orange) + {0.8f, 1.0f, 0.0f}, // #ccff00 (yellow) + {0.2f, 1.0f, 0.2f}, // #00ff33 (green) + {0.0f, 0.8f, 1.0f}, // #00ccff (sky blue) + {0.4f, 0.4f, 1.0f}, // #6666ff (blue) + {0.8f, 0.0f, 1.0f}, // #cc00ff (purple) + {1.0f, 0.2f, 0.8f}, // #ff33cc (pink) }; -int MAX_EFFECTS_PER_HITBOX = 16; // max # of circles drawn for an extended hitbox +int MAX_EFFECTS_PER_HITBOX = 16; // max # of circles drawn for an extended hitbox namespace app::lua_bind::AttackModule { - // clear graphics every time we clear all hitboxes - void clear_all_replace(u64 module_accessor) { - if (is_training_mode()) { - // only if we're not shielding - int status_kind = StatusModule::status_kind(module_accessor); - if (!(status_kind >= FIGHTER_STATUS_KIND_GUARD_ON && status_kind <= FIGHTER_STATUS_KIND_GUARD_OFF)) { - Hash40 shieldEffectHash = { .hash = 0xAFAE75F05LL }; - EffectModule::kill_kind(module_accessor, shieldEffectHash.hash, 0, 1); - } - } +// clear graphics every time we clear all hitboxes +void clear_all_replace(u64 module_accessor) { + if (is_training_mode()) { + // only if we're not shielding + int status_kind = StatusModule::status_kind(module_accessor); + if (!(status_kind >= FIGHTER_STATUS_KIND_GUARD_ON && + status_kind <= FIGHTER_STATUS_KIND_GUARD_OFF)) { + Hash40 shieldEffectHash = {.hash = 0xAFAE75F05LL}; + EffectModule::kill_kind(module_accessor, shieldEffectHash.hash, 0, 1); + } + } - // call original AttackModule::clear_all_impl - u64 attack_module = load_module(module_accessor, 0xA0); - void (*clear_all)(u64) = (void(*)(u64))(load_module_impl(attack_module, 0x50)); + // call original AttackModule::clear_all_impl + u64 attack_module = load_module(module_accessor, 0xA0); + void (*clear_all)(u64) = + (void (*)(u64))(load_module_impl(attack_module, 0x50)); - return clear_all(attack_module); - } + return clear_all(attack_module); } +} // namespace app::lua_bind::AttackModule namespace app::lua_bind::GrabModule { - // clear graphics every time we clear rebound - void set_rebound_replace(u64 module_accessor, bool rebound) { - if (is_training_mode() && rebound == false) { - // only if we're not shielding - int status_kind = StatusModule::status_kind(module_accessor); - if (!(status_kind >= FIGHTER_STATUS_KIND_GUARD_ON && status_kind <= FIGHTER_STATUS_KIND_GUARD_OFF)) { - Hash40 shieldEffectHash = { .hash = 0xAFAE75F05LL }; - EffectModule::kill_kind(module_accessor, shieldEffectHash.hash, 0, 1); - } - } - - // call original GrabModule::set_rebound_impl - u64 grab_module = load_module(module_accessor, 0x158); - void (*set_rebound)(u64, bool) = (void(*)(u64, bool))(load_module_impl(grab_module, 0x100)); - - return set_rebound(grab_module, rebound); - } -} - -Vector3f EffectModule_last_get_scale_w(u64 effect_module) -{ - Vector3f ret; - uint handle = *(uint *)(effect_module + 36); - if ( handle && (signed int)handle >= 1 ) - { - u64 effect = LOAD64(effect_manager_addr) + 768 * (handle >> 24); - bool is_exist_effect = effect && *(uint *)(effect + 4) == handle; - if ( is_exist_effect ) - { - float* scale = (float*)(effect + 256); - ret.x = *(float *)(scale); - ret.y = *(float *)(scale+1); - ret.z = *(float *)(scale+2); +// clear graphics every time we clear rebound +void set_rebound_replace(u64 module_accessor, bool rebound) { + if (is_training_mode() && rebound == false) { + // only if we're not shielding + int status_kind = StatusModule::status_kind(module_accessor); + if (!(status_kind >= FIGHTER_STATUS_KIND_GUARD_ON && + status_kind <= FIGHTER_STATUS_KIND_GUARD_OFF)) { + Hash40 shieldEffectHash = {.hash = 0xAFAE75F05LL}; + EffectModule::kill_kind(module_accessor, shieldEffectHash.hash, 0, 1); + } } - } - return ret; + + // call original GrabModule::set_rebound_impl + u64 grab_module = load_module(module_accessor, 0x158); + void (*set_rebound)(u64, bool) = + (void (*)(u64, bool))(load_module_impl(grab_module, 0x100)); + + return set_rebound(grab_module, rebound); +} +} // namespace app::lua_bind::GrabModule + +Vector3f EffectModule_last_get_scale_w(u64 effect_module) { + Vector3f ret; + uint handle = *(uint *)(effect_module + 36); + if (handle && (signed int)handle >= 1) { + u64 effect = LOAD64(effect_manager_addr) + 768 * (handle >> 24); + bool is_exist_effect = effect && *(uint *)(effect + 4) == handle; + if (is_exist_effect) { + float *scale = (float *)(effect + 256); + ret.x = *(float *)(scale); + ret.y = *(float *)(scale + 1); + ret.z = *(float *)(scale + 2); + } + } + return ret; } -void generate_hitbox_effects(L2CAgent *l2c_agent, L2CValue *bone, L2CValue *size, - L2CValue *x, L2CValue *y, L2CValue *z, L2CValue *x2, L2CValue *y2, L2CValue *z2, - Vector3f *color) { - L2CValue red(color->x); - L2CValue green(color->y); - L2CValue blue(color->z); +void generate_hitbox_effects(L2CAgent *l2c_agent, L2CValue *bone, + L2CValue *size, L2CValue *x, L2CValue *y, + L2CValue *z, L2CValue *x2, L2CValue *y2, + L2CValue *z2, Vector3f *color) { + L2CValue red(color->x); + L2CValue green(color->y); + L2CValue blue(color->z); - float size_mult = 19.0f / 200.0f; - Hash40 shield_effect_hash = { .hash = 0xAFAE75F05LL }; + float size_mult = 19.0f / 200.0f; + Hash40 shield_effect_hash = {.hash = 0xAFAE75F05LL}; - L2CValue shieldEffect(shield_effect_hash.hash); - L2CValue x_rot(0.0f); - L2CValue y_rot(0.0f); - L2CValue z_rot(0.0f); - L2CValue terminate(true); - L2CValue effect_size((float)size->raw_float * size_mult); + L2CValue shieldEffect(shield_effect_hash.hash); + L2CValue x_rot(0.0f); + L2CValue y_rot(0.0f); + L2CValue z_rot(0.0f); + L2CValue terminate(true); + L2CValue effect_size((float)size->raw_float * size_mult); - L2CValue rate(8.0f); + L2CValue rate(8.0f); - float x_dist, y_dist, z_dist; - int n_effects; - if (x2->type != L2C_void && y2->type != L2C_void && z2->type != L2C_void) { // extended hitbox - x_dist = x2->raw_float - x->raw_float; - y_dist = y2->raw_float - y->raw_float; - z_dist = z2->raw_float - z->raw_float; - float dist = sqrtf(x_dist * x_dist + y_dist * y_dist + z_dist * z_dist); - n_effects = (int)ceilf(dist / (size->raw_float * 1.75f)) + 1; // just enough effects to form a continuous line - if (n_effects < 2) - n_effects = 2; - if (n_effects > MAX_EFFECTS_PER_HITBOX) - n_effects = MAX_EFFECTS_PER_HITBOX; - } else { // non-extended hitbox - x_dist = y_dist = z_dist = 0; - n_effects = 1; - } + float x_dist, y_dist, z_dist; + int n_effects; + if (x2->type != L2C_void && y2->type != L2C_void && + z2->type != L2C_void) { // extended hitbox + x_dist = x2->raw_float - x->raw_float; + y_dist = y2->raw_float - y->raw_float; + z_dist = z2->raw_float - z->raw_float; + float dist = sqrtf(x_dist * x_dist + y_dist * y_dist + z_dist * z_dist); + n_effects = (int)ceilf(dist / (size->raw_float * 1.75f)) + 1; // just enough effects to form a continuous line + if (n_effects < 2) n_effects = 2; + if (n_effects > MAX_EFFECTS_PER_HITBOX) + n_effects = MAX_EFFECTS_PER_HITBOX; + } else { // non-extended hitbox + x_dist = y_dist = z_dist = 0; + n_effects = 1; + } - for (int i = 0; i < n_effects; i++) { - float t = n_effects <= 1 ? 0 : (float)i / (n_effects - 1); - L2CValue x_curr(x->raw_float + x_dist * t); - L2CValue y_curr(y->raw_float + y_dist * t); - L2CValue z_curr(z->raw_float + z_dist * t); + for (int i = 0; i < n_effects; i++) { + float t = n_effects <= 1 ? 0 : (float)i / (n_effects - 1); + L2CValue x_curr(x->raw_float + x_dist * t); + L2CValue y_curr(y->raw_float + y_dist * t); + L2CValue z_curr(z->raw_float + z_dist * t); - ACMD acmd(l2c_agent); - acmd.wrap(EFFECT_FOLLOW_NO_SCALE, { shieldEffect, *bone, x_curr, y_curr, z_curr, x_rot, y_rot, z_rot, effect_size, terminate }); - - // set to hitbox ID color - acmd.wrap(LAST_EFFECT_SET_COLOR, { red, green, blue }); + ACMD acmd(l2c_agent); + acmd.wrap(EFFECT_FOLLOW_NO_SCALE, + {shieldEffect, *bone, x_curr, y_curr, z_curr, x_rot, y_rot, + z_rot, effect_size, terminate}); - // speed up animation by rate to remove pulsing effect - acmd.wrap(LAST_EFFECT_SET_RATE, { rate }); - } + // set to hitbox ID color + acmd.wrap(LAST_EFFECT_SET_COLOR, {red, green, blue}); + + // speed up animation by rate to remove pulsing effect + acmd.wrap(LAST_EFFECT_SET_RATE, {rate}); + } } namespace app::sv_animcmd { - void ATTACK_replace(u64 a1) { - // instantiate our own L2CAgent with the given lua_State - L2CAgent l2c_agent; - l2c_agent.L2CAgent_constr(a1); +void ATTACK_replace(u64 a1) { + // instantiate our own L2CAgent with the given lua_State + L2CAgent l2c_agent; + l2c_agent.L2CAgent_constr(a1); - // get all necessary hitbox params - L2CValue id, bone, damage, angle, kbg, fkb, bkb, size, x, y, z, x2, y2, z2; - l2c_agent.get_lua_stack(1, &id); // int - l2c_agent.get_lua_stack(3, &bone); // hash40 - l2c_agent.get_lua_stack(4, &damage); // float - l2c_agent.get_lua_stack(5, &angle); // int - l2c_agent.get_lua_stack(6, &kbg); // int - l2c_agent.get_lua_stack(7, &fkb); // int - l2c_agent.get_lua_stack(8, &bkb); // int - l2c_agent.get_lua_stack(9, &size); // float - l2c_agent.get_lua_stack(10, &x); // float - l2c_agent.get_lua_stack(11, &y); // float - l2c_agent.get_lua_stack(12, &z); // float - l2c_agent.get_lua_stack(13, &x2); // float or void - l2c_agent.get_lua_stack(14, &y2); // float or void - l2c_agent.get_lua_stack(15, &z2); // float or void + // get all necessary hitbox params + L2CValue id, bone, damage, angle, kbg, fkb, bkb, size, x, y, z, x2, y2, z2; + l2c_agent.get_lua_stack(1, &id); // int + l2c_agent.get_lua_stack(3, &bone); // hash40 + l2c_agent.get_lua_stack(4, &damage); // float + l2c_agent.get_lua_stack(5, &angle); // int + l2c_agent.get_lua_stack(6, &kbg); // int + l2c_agent.get_lua_stack(7, &fkb); // int + l2c_agent.get_lua_stack(8, &bkb); // int + l2c_agent.get_lua_stack(9, &size); // float + l2c_agent.get_lua_stack(10, &x); // float + l2c_agent.get_lua_stack(11, &y); // float + l2c_agent.get_lua_stack(12, &z); // float + l2c_agent.get_lua_stack(13, &x2); // float or void + l2c_agent.get_lua_stack(14, &y2); // float or void + l2c_agent.get_lua_stack(15, &z2); // float or void - // hacky way of forcing no shield damage on all hitboxes - if (is_training_mode() && TOGGLE_STATE == INFINITE_SHIELD) { - L2CValue hitbox_params[36]; - for (size_t i = 0; i < 36; i++) - l2c_agent.get_lua_stack(i+1, &hitbox_params[i]); - - l2c_agent.clear_lua_stack(); + // hacky way of forcing no shield damage on all hitboxes + if (is_training_mode() && TOGGLE_STATE == INFINITE_SHIELD) { + L2CValue hitbox_params[36]; + for (size_t i = 0; i < 36; i++) + l2c_agent.get_lua_stack(i + 1, &hitbox_params[i]); - for (size_t i = 0; i < 36; i++) { - if (i == 20) { - L2CValue no_shield_damage(-999); - l2c_agent.push_lua_stack(&no_shield_damage); - } - else - l2c_agent.push_lua_stack(&hitbox_params[i]); - } - } + l2c_agent.clear_lua_stack(); - // original code: parse lua stack and call AttackModule::set_attack() - AttackModule_set_attack_lua_state(LOAD64(LOAD64(a1 - 8) + 416LL), a1); + for (size_t i = 0; i < 36; i++) { + if (i == 20) { + L2CValue no_shield_damage(-999); + l2c_agent.push_lua_stack(&no_shield_damage); + } else + l2c_agent.push_lua_stack(&hitbox_params[i]); + } + } - if (HITBOX_VIS && is_training_mode()) { // generate hitbox effect(s) - float color_scale; - if (false) { // color intensity scales with damage - color_scale = unlerp_bounded(1.0f, 18.0f, damage.raw_float); - } else { // color intensity scales with total KB - // calculate the expected KB a character with 95 weight will receive at 80% pre-hit - float TARGET_PERCENT = 80.0f; - int TARGET_WEIGHT = 95; - float percent_component; - if (fkb.raw > 0) { - percent_component = (10.0f + fkb.raw) * 0.1f * (1.0f + fkb.raw * 0.5f); - } else { - percent_component = (TARGET_PERCENT + damage.raw_float) * 0.1f * (1.0f + damage.raw_float * 0.5f); - } - float weight_component = 200.0f / (TARGET_WEIGHT + 100); - float kb = (percent_component * weight_component * 1.4f + 18.0f) * (kbg.raw * 0.01f) + bkb.raw; - color_scale = unlerp_bounded(50.0f, 200.0f, kb); - } - float color_t = 0.8f + 0.2f * powf(color_scale, 0.5f); // non-linear scaling to magnify differences at lower values - Vector3f color = color_lerp({ 1.0f, 1.0f, 1.0f }, ID_COLORS[id.raw % 8], color_t); - generate_hitbox_effects(&l2c_agent, &bone, &size, &x, &y, &z, &x2, &y2, &z2, &color); - } + // original code: parse lua stack and call AttackModule::set_attack() + AttackModule_set_attack_lua_state(LOAD64(LOAD64(a1 - 8) + 416LL), a1); - u64 v1, v2, i; - v1 = a1; + if (HITBOX_VIS && is_training_mode()) { // generate hitbox effect(s) + float color_scale; + if (false) { // color intensity scales with damage + color_scale = unlerp_bounded(1.0f, 18.0f, damage.raw_float); + } else { // color intensity scales with total KB + // calculate the expected KB a character with 95 weight will receive + // at 80% pre-hit + float TARGET_PERCENT = 80.0f; + int TARGET_WEIGHT = 95; + float percent_component; + if (fkb.raw > 0) { + percent_component = + (10.0f + fkb.raw) * 0.1f * (1.0f + fkb.raw * 0.5f); + } else { + percent_component = (TARGET_PERCENT + damage.raw_float) * 0.1f * + (1.0f + damage.raw_float * 0.5f); + } + float weight_component = 200.0f / (TARGET_WEIGHT + 100); + float kb = (percent_component * weight_component * 1.4f + 18.0f) * + (kbg.raw * 0.01f) + + bkb.raw; + color_scale = unlerp_bounded(50.0f, 200.0f, kb); + } + float color_t = + 0.8f + + 0.2f * powf(color_scale, 0.5f); // non-linear scaling to magnify + // differences at lower values + Vector3f color = color_lerp({1.0f, 1.0f, 1.0f}, ID_COLORS[id.raw % 8], color_t); + generate_hitbox_effects(&l2c_agent, &bone, &size, &x, &y, &z, &x2, &y2, &z2, &color); + } - // original code: clear_lua_stack section - v2 = LOAD64(v1 + 16); - for (i = **(u64 **)(v1 + 32) + 16LL; v2 < i; v2 = LOAD64(v1 + 16)) { - LOAD64(v1 + 16) = v2 + 16; - *(__int32_t *)(v2 + 8) = 0; - } - LOAD64(v1 + 16) = i; - } + u64 v1, v2, i; + v1 = a1; - void CATCH_replace(u64 a1) { - L2CAgent l2c_agent; - l2c_agent.L2CAgent_constr(a1); - - // get all necessary grabbox params - L2CValue id, joint, size, x, y, z, x2, y2, z2; - l2c_agent.get_lua_stack(1, &id); // int - l2c_agent.get_lua_stack(2, &joint); // hash40 - l2c_agent.get_lua_stack(3, &size); // float - l2c_agent.get_lua_stack(4, &x); // float - l2c_agent.get_lua_stack(5, &y); // float - l2c_agent.get_lua_stack(6, &z); // float - l2c_agent.get_lua_stack(7, &x2); // float or void - l2c_agent.get_lua_stack(8, &y2); // float or void - l2c_agent.get_lua_stack(9, &z2); // float or void - - // SaltySD_function_replace_sym works by replacing the - // first four instructions of a function with instructions - // to jump to a replacement function like CATCH_replace. - // if we want to jump back, we just need to reimplement the - // first four instructions and jump back to the original address - // + the length of 4 instructions - - // load address, along with lua_state as first arg - asm("MOV X9, %x0" : : "r"(Catch_jumpback)); - asm("MOV X0, %x0" : : "r"(l2c_agent.lua_state_agent)); - - // the first four instructions: they will usually be - // setting up the stack for local variables - asm("SUB SP, SP, #0xC0"); - asm("STR X25, [SP, #0x70]"); - asm("STP X24, X23, [SP, #0x80]"); - asm("STP X22, X21, [SP, #0x90]"); - - // jump to Catch_jumpback - asm("BLR X9"); - - if (HITBOX_VIS && is_training_mode()) { - Vector3f color = ID_COLORS[(id.raw + 3) % 8]; - generate_hitbox_effects(&l2c_agent, &joint, &size, &x, &y, &z, &x2, &y2, &z2, &color); - } - } + // original code: clear_lua_stack section + v2 = LOAD64(v1 + 16); + for (i = **(u64 **)(v1 + 32) + 16LL; v2 < i; v2 = LOAD64(v1 + 16)) { + LOAD64(v1 + 16) = v2 + 16; + *(__int32_t *)(v2 + 8) = 0; + } + LOAD64(v1 + 16) = i; } +void CATCH_replace(u64 a1) { + L2CAgent l2c_agent; + l2c_agent.L2CAgent_constr(a1); + + // get all necessary grabbox params + L2CValue id, joint, size, x, y, z, x2, y2, z2; + l2c_agent.get_lua_stack(1, &id); // int + l2c_agent.get_lua_stack(2, &joint); // hash40 + l2c_agent.get_lua_stack(3, &size); // float + l2c_agent.get_lua_stack(4, &x); // float + l2c_agent.get_lua_stack(5, &y); // float + l2c_agent.get_lua_stack(6, &z); // float + l2c_agent.get_lua_stack(7, &x2); // float or void + l2c_agent.get_lua_stack(8, &y2); // float or void + l2c_agent.get_lua_stack(9, &z2); // float or void + + // SaltySD_function_replace_sym works by replacing the + // first four instructions of a function with instructions + // to jump to a replacement function like CATCH_replace. + // if we want to jump back, we just need to reimplement the + // first four instructions and jump back to the original address + // + the length of 4 instructions + + // load address, along with lua_state as first arg + asm("MOV X9, %x0" : : "r"(Catch_jumpback)); + asm("MOV X0, %x0" : : "r"(l2c_agent.lua_state_agent)); + + // the first four instructions: they will usually be + // setting up the stack for local variables + asm("SUB SP, SP, #0xC0"); + asm("STR X25, [SP, #0x70]"); + asm("STP X24, X23, [SP, #0x80]"); + asm("STP X22, X21, [SP, #0x90]"); + + // jump to Catch_jumpback + asm("BLR X9"); + + if (HITBOX_VIS && is_training_mode()) { + Vector3f color = ID_COLORS[(id.raw + 3) % 8]; + generate_hitbox_effects(&l2c_agent, &joint, &size, &x, &y, &z, &x2, &y2, &z2, &color); + } +} +} // namespace app::sv_animcmd + void hitbox_vis_main() { - effect_manager_addr = SaltySDCore_FindSymbol("_ZN3lib9SingletonINS_13EffectManagerEE9instance_E"); + effect_manager_addr = SaltySDCore_FindSymbol( + "_ZN3lib9SingletonINS_13EffectManagerEE9instance_E"); - AttackModule_set_attack_lua_state = (void (*)(u64, u64))SaltySDCore_FindSymbol("_ZN3app10sv_animcmd6ATTACKEP9lua_State") + 0xD0 - 0x70; - Catch_jumpback = SaltySDCore_FindSymbol("_ZN3app10sv_animcmd5CATCHEP9lua_State") + (4*4); - SaltySD_function_replace_sym( - "_ZN3app10sv_animcmd6ATTACKEP9lua_State", - (u64)&ATTACK_replace); + AttackModule_set_attack_lua_state = (void (*)(u64, u64))SaltySDCore_FindSymbol("_ZN3app10sv_animcmd6ATTACKEP9lua_State") + + 0xD0 - 0x70; + Catch_jumpback = SaltySDCore_FindSymbol("_ZN3app10sv_animcmd5CATCHEP9lua_State") + (4 * 4); + SaltySD_function_replace_sym("_ZN3app10sv_animcmd6ATTACKEP9lua_State", + (u64)&ATTACK_replace); - SaltySD_function_replace_sym( - "_ZN3app10sv_animcmd5CATCHEP9lua_State", - (u64)&CATCH_replace); + SaltySD_function_replace_sym("_ZN3app10sv_animcmd5CATCHEP9lua_State", + (u64)&CATCH_replace); - SaltySD_function_replace_sym( - "_ZN3app8lua_bind28AttackModule__clear_all_implEPNS_26BattleObjectModuleAccessorE", - (u64)&AttackModule::clear_all_replace); + SaltySD_function_replace_sym( + "_ZN3app8lua_bind28AttackModule__clear_all_implEPNS_26BattleObjectModuleAccessorE", + (u64)&AttackModule::clear_all_replace); - SaltySD_function_replace_sym( - "_ZN3app8lua_bind28GrabModule__set_rebound_implEPNS_26BattleObjectModuleAccessorEb", - (u64)&GrabModule::set_rebound_replace); + SaltySD_function_replace_sym( + "_ZN3app8lua_bind28GrabModule__set_rebound_implEPNS_26BattleObjectModuleAccessorEb", + (u64)&GrabModule::set_rebound_replace); } -#endif // HITBOX_VISUALIZER_H +#endif // HITBOX_VISUALIZER_H diff --git a/source/main.cpp b/source/main.cpp index 6d6260c..6f19d18 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -1,36 +1,36 @@ #include <switch.h> -#include <string.h> -#include <stdio.h> #include <dirent.h> +#include <stdio.h> +#include <string.h> +#include <switch/kernel/ipc.h> #include <sys/iosupport.h> #include <sys/reent.h> -#include <switch/kernel/ipc.h> #include "useful/useful.h" #include "saltysd/saltysd_core.h" -#include "saltysd/saltysd_ipc.h" #include "saltysd/saltysd_dynamic.h" +#include "saltysd/saltysd_ipc.h" -#include "saltysd/saltysd_helper.hpp" -#include "imports/lib/l2c.hpp" #include "imports/app/sv_animcmd.hpp" +#include "imports/lib/l2c.hpp" +#include "saltysd/saltysd_helper.hpp" #include "hitbox_visualizer.hpp" #include "script_replacement.hpp" #include "training_mods.hpp" extern "C" { - extern u32 __start__; +extern u32 __start__; - static char g_heap[0x8000]; +static char g_heap[0x8000]; - void __libnx_init(void* ctx, Handle main_thread, void* saved_lr); - void __attribute__((weak)) NORETURN __libnx_exit(int rc); - void __nx_exit(int, void*); - void __libc_fini_array(void); - void __libc_init_array(void); +void __libnx_init(void* ctx, Handle main_thread, void* saved_lr); +void __attribute__((weak)) NORETURN __libnx_exit(int rc); +void __nx_exit(int, void*); +void __libc_fini_array(void); +void __libc_init_array(void); } u32 __nx_applet_type = AppletType_None; @@ -40,57 +40,59 @@ void* orig_ctx; void* orig_saved_lr; void __libnx_init(void* ctx, Handle main_thread, void* saved_lr) { - extern char* fake_heap_start; - extern char* fake_heap_end; + extern char* fake_heap_start; + extern char* fake_heap_end; - fake_heap_start = &g_heap[0]; - fake_heap_end = &g_heap[sizeof g_heap]; - - orig_ctx = ctx; - orig_main_thread = main_thread; - orig_saved_lr = saved_lr; - - // Call constructors. - //void __libc_init_array(void); - __libc_init_array(); + fake_heap_start = &g_heap[0]; + fake_heap_end = &g_heap[sizeof g_heap]; + + orig_ctx = ctx; + orig_main_thread = main_thread; + orig_saved_lr = saved_lr; + + // Call constructors. + // void __libc_init_array(void); + __libc_init_array(); } void __attribute__((weak)) NORETURN __libnx_exit(int rc) { - // Call destructors. - //void __libc_fini_array(void); - __libc_fini_array(); + // Call destructors. + // void __libc_fini_array(void); + __libc_fini_array(); - SaltySD_printf("SaltySD Plugin: jumping to %p\n", orig_saved_lr); + SaltySD_printf("SaltySD Plugin: jumping to %p\n", orig_saved_lr); - __nx_exit(0, orig_saved_lr); - while (true); + __nx_exit(0, orig_saved_lr); + while (true) + ; } -int main(int argc, char *argv[]) { - SaltySD_printf("SaltySD Plugin: alive\n"); - - // Get anchor for imports - // do not remove if you plan on using IMPORT - ANCHOR_ABS = SaltySDCore_getCodeStart(); +int main(int argc, char* argv[]) { + SaltySD_printf("SaltySD Plugin: alive\n"); - /* - Example of string replacement: - replaces the title screen's version number with the string - below. - */ - - const char *ver = "Ver. %d.%d.%d"; - u64 version_string = SaltySDCore_findCode((u8 *)ver, strlen(ver)); - if (version_string) { - SaltySD_Memcpy(version_string, (u64) "Salty v%d%d%d", 13); - } + // Get anchor for imports + // do not remove if you plan on using IMPORT + ANCHOR_ABS = SaltySDCore_getCodeStart(); - // Necessary for script replacement - SaltySD_function_replace_sym("_ZN3lib8L2CAgent15clear_lua_stackEv", (u64) &clear_lua_stack_replace); - - // Add function replacements here - hitbox_vis_main(); - training_mods_main(); + /* + Example of string replacement: + replaces the title screen's version number with the string + below. + */ - __libnx_exit(0); + const char* ver = "Ver. %d.%d.%d"; + u64 version_string = SaltySDCore_findCode((u8*)ver, strlen(ver)); + if (version_string) { + SaltySD_Memcpy(version_string, (u64) "Salty v%d%d%d", 13); + } + + // Necessary for script replacement + SaltySD_function_replace_sym("_ZN3lib8L2CAgent15clear_lua_stackEv", + (u64)&clear_lua_stack_replace); + + // Add function replacements here + hitbox_vis_main(); + training_mods_main(); + + __libnx_exit(0); } diff --git a/source/script_replacement.hpp b/source/script_replacement.hpp index 4f5f6c8..1de86a1 100644 --- a/source/script_replacement.hpp +++ b/source/script_replacement.hpp @@ -8,15 +8,16 @@ #include "useful/const_value_table.h" #include "useful/raygun_printer.hpp" -#include "imports/lib/l2c.hpp" #include "acmd_wrapper.hpp" +#include "imports/lib/l2c.hpp" #include "taunt_toggles.h" using namespace lib; using namespace app::lua_bind; -void sv_replace_status_func(u64 l2c_agentbase, int status_kind, u64 key, void* func); +void sv_replace_status_func(u64 l2c_agentbase, int status_kind, u64 key, + void* func); u64 appeal_lw_replace(L2CAgent* l2c_agent, void* variadic); u64 appeal_hi_replace(L2CAgent* l2c_agent, void* variadic); @@ -26,146 +27,128 @@ u64 pre_GuardDamage_replace(L2CAgent* l2c_fighter, L2CAgent* l2c_agent); void replace_scripts(L2CAgent* l2c_agent, u8 category, int kind) { // fighter if (category == BATTLE_OBJECT_CATEGORY_FIGHTER) { - // taunt toggles - l2c_agent->sv_set_function_hash(&appeal_lw_replace, hash40("effect_appeallwl")); - l2c_agent->sv_set_function_hash(&appeal_lw_replace, hash40("effect_appeallwr")); - l2c_agent->sv_set_function_hash(&appeal_hi_replace, hash40("effect_appealhil")); - l2c_agent->sv_set_function_hash(&appeal_hi_replace, hash40("effect_appealhir")); - l2c_agent->sv_set_function_hash(&appeal_s_replace, hash40("effect_appealsl")); - l2c_agent->sv_set_function_hash(&appeal_s_replace, hash40("effect_appealsr")); + // taunt toggles + l2c_agent->sv_set_function_hash(&appeal_lw_replace, + hash40("effect_appeallwl")); + l2c_agent->sv_set_function_hash(&appeal_lw_replace, + hash40("effect_appeallwr")); + l2c_agent->sv_set_function_hash(&appeal_hi_replace, + hash40("effect_appealhil")); + l2c_agent->sv_set_function_hash(&appeal_hi_replace, + hash40("effect_appealhir")); + l2c_agent->sv_set_function_hash(&appeal_s_replace, + hash40("effect_appealsl")); + l2c_agent->sv_set_function_hash(&appeal_s_replace, + hash40("effect_appealsr")); } } u64 appeal_lw_replace(L2CAgent* l2c_agent, void* variadic) { ACMD acmd = ACMD(l2c_agent); - + acmd.frame(1); if (acmd.is_excute()) { - if (is_training_mode()) { - TOGGLE_STATE = (TOGGLE_STATE + 1) % NUM_TOGGLE_STATES; - const char* toggle_strings[NUM_TOGGLE_STATES] = { - "NONE", - "MASH\nAIRDODGE", - "MASH\nJUMP", - "MASH\nATTACK", - "MASH\nRANDOM", - "INFINITE\nSHIELD", - "HOLD\nSHIELD", - "LEDGE\nOPTION" - }; - - print_string(acmd.module_accessor, toggle_strings[TOGGLE_STATE]); - } + if (is_training_mode()) { + TOGGLE_STATE = (TOGGLE_STATE + 1) % NUM_TOGGLE_STATES; + const char* toggle_strings[NUM_TOGGLE_STATES] = { + "NONE", "MASH\nAIRDODGE", "MASH\nJUMP", + "MASH\nATTACK", "MASH\nRANDOM", "INFINITE\nSHIELD", + "HOLD\nSHIELD", "LEDGE\nOPTION"}; + + print_string(acmd.module_accessor, toggle_strings[TOGGLE_STATE]); + } } return 0; } u64 appeal_hi_replace(L2CAgent* l2c_agent, void* variadic) { - ACMD acmd = ACMD(l2c_agent); + ACMD acmd = ACMD(l2c_agent); - acmd.frame(1); - if (acmd.is_excute()) { - if (is_training_mode()) { - HITBOX_VIS = !HITBOX_VIS; - if (HITBOX_VIS) - print_string(acmd.module_accessor, "HITBOX\nVIS"); - else - print_string(acmd.module_accessor, "NO\nHITBOX"); - } - } + acmd.frame(1); + if (acmd.is_excute()) { + if (is_training_mode()) { + HITBOX_VIS = !HITBOX_VIS; + if (HITBOX_VIS) + print_string(acmd.module_accessor, "HITBOX\nVIS"); + else + print_string(acmd.module_accessor, "NO\nHITBOX"); + } + } - return 0; + return 0; } u64 appeal_s_replace(L2CAgent* l2c_agent, void* variadic) { - ACMD acmd = ACMD(l2c_agent); + ACMD acmd = ACMD(l2c_agent); - acmd.frame(1); - if (acmd.is_excute()) { - if (is_training_mode()) { - if (TOGGLE_STATE == LEDGE_OPTION) { - LEDGE_STATE = (LEDGE_STATE + 1) % NUM_LEDGE_STATES; - const char* LEDGE_strings[NUM_LEDGE_STATES] = { - "RANDOM", - "NORMAL", - "ROLL", - "JUMP", - "ATTACK" - }; + acmd.frame(1); + if (acmd.is_excute()) { + if (is_training_mode()) { + if (TOGGLE_STATE == LEDGE_OPTION) { + LEDGE_STATE = (LEDGE_STATE + 1) % NUM_LEDGE_STATES; + const char* LEDGE_strings[NUM_LEDGE_STATES] = { + "RANDOM", "NORMAL", "ROLL", "JUMP", "ATTACK"}; - print_string(acmd.module_accessor, LEDGE_strings[LEDGE_STATE]); - } else if (TOGGLE_STATE == MASH_ATTACK) { - ATTACK_STATE = (ATTACK_STATE + 1) % NUM_ATTACK_STATES; - const char* ATTACK_strings[NUM_ATTACK_STATES] = { - "NAIR", - "FAIR", - "BAIR", - "UPAIR", - "DAIR", - "NEUTRAL B", - "SIDE B", - "UP B", - "DOWN B" - }; + print_string(acmd.module_accessor, LEDGE_strings[LEDGE_STATE]); + } else if (TOGGLE_STATE == MASH_ATTACK) { + ATTACK_STATE = (ATTACK_STATE + 1) % NUM_ATTACK_STATES; + const char* ATTACK_strings[NUM_ATTACK_STATES] = { + "NAIR", "FAIR", "BAIR", "UPAIR", "DAIR", + "NEUTRAL B", "SIDE B", "UP B", "DOWN B"}; - print_string(acmd.module_accessor, ATTACK_strings[ATTACK_STATE]); - } else { - DI_STATE = (DI_STATE + 1) % NUM_DI_STATES; - const char* DI_strings[NUM_DI_STATES] = { - "NONE", - "AWAY", - "DOWN AWAY", - "DOWN", - "DOWN IN", - "IN", - "UP IN", - "UP", - "UP AWAY", - "RANDOM\nIN AWAY" - }; + print_string(acmd.module_accessor, + ATTACK_strings[ATTACK_STATE]); + } else { + DI_STATE = (DI_STATE + 1) % NUM_DI_STATES; + const char* DI_strings[NUM_DI_STATES] = { + "NONE", "AWAY", "DOWN AWAY", "DOWN", "DOWN IN", + "IN", "UP IN", "UP", "UP AWAY", "RANDOM\nIN AWAY"}; - print_string(acmd.module_accessor, DI_strings[DI_STATE]); - } - } - } + print_string(acmd.module_accessor, DI_strings[DI_STATE]); + } + } + } - return 0; + return 0; } void* sv_get_status_func(u64 l2c_agentbase, int status_kind, u64 key) { - u64 unk48 = LOAD64(l2c_agentbase + 0x48); - u64 unk50 = LOAD64(l2c_agentbase + 0x50); - if (0x2E8BA2E8BA2E8BA3LL * ((unk50 - unk48) >> 4) > (u64)status_kind) - return *(void **)(unk48 + 0xB0LL * status_kind + (key << 32 >> 29)); + u64 unk48 = LOAD64(l2c_agentbase + 0x48); + u64 unk50 = LOAD64(l2c_agentbase + 0x50); + if (0x2E8BA2E8BA2E8BA3LL * ((unk50 - unk48) >> 4) > (u64)status_kind) + return *(void**)(unk48 + 0xB0LL * status_kind + (key << 32 >> 29)); - return 0; + return 0; } -void sv_replace_status_func(u64 l2c_agentbase, int status_kind, u64 key, void* func) { - u64 unk48 = LOAD64(l2c_agentbase + 0x48); - u64 unk50 = LOAD64(l2c_agentbase + 0x50); - if (0x2E8BA2E8BA2E8BA3LL * ((unk50 - unk48) >> 4) > (u64)status_kind) { - *(void **)(unk48 + 0xB0LL * status_kind + (key << 32 >> 29)) = func; - } +void sv_replace_status_func(u64 l2c_agentbase, int status_kind, u64 key, + void* func) { + u64 unk48 = LOAD64(l2c_agentbase + 0x48); + u64 unk50 = LOAD64(l2c_agentbase + 0x50); + if (0x2E8BA2E8BA2E8BA3LL * ((unk50 - unk48) >> 4) > (u64)status_kind) { + *(void**)(unk48 + 0xB0LL * status_kind + (key << 32 >> 29)) = func; + } } u64 clear_lua_stack_replace(u64 l2c_agent) { - u64 lua_state = LOAD64(l2c_agent + 8); - if ((lua_state - 8) && LOAD64(lua_state - 8) && (LOAD64(LOAD64(lua_state - 8) + 416LL))) { - u8 battle_object_category = *(u8 *)(LOAD64(lua_state - 8) + 404LL); - int battle_object_kind = *(int *)(LOAD64(lua_state - 8) + 408LL); - replace_scripts((L2CAgent*)l2c_agent, battle_object_category, battle_object_kind); - } + u64 lua_state = LOAD64(l2c_agent + 8); + if ((lua_state - 8) && LOAD64(lua_state - 8) && + (LOAD64(LOAD64(lua_state - 8) + 416LL))) { + u8 battle_object_category = *(u8*)(LOAD64(lua_state - 8) + 404LL); + int battle_object_kind = *(int*)(LOAD64(lua_state - 8) + 408LL); + replace_scripts((L2CAgent*)l2c_agent, battle_object_category, + battle_object_kind); + } - // Original clear_lua_stack: - u64 v1 = LOAD64(l2c_agent + 8); - u64 v2 = LOAD64(v1 + 16); - u64 i = LOAD64(LOAD64(v1 + 32)) + 16LL; - for (; v2 < i; v2 = LOAD64(v1 + 16)) { - LOAD64(v1 + 16) = v2 + 16; - *(u32 *)(v2 + 8) = 0; - } - LOAD64(v1 + 16) = i; - return l2c_agent; + // Original clear_lua_stack: + u64 v1 = LOAD64(l2c_agent + 8); + u64 v2 = LOAD64(v1 + 16); + u64 i = LOAD64(LOAD64(v1 + 32)) + 16LL; + for (; v2 < i; v2 = LOAD64(v1 + 16)) { + LOAD64(v1 + 16) = v2 + 16; + *(u32*)(v2 + 8) = 0; + } + LOAD64(v1 + 16) = i; + return l2c_agent; } diff --git a/source/training_mods.hpp b/source/training_mods.hpp index a33b90f..e4526fd 100644 --- a/source/training_mods.hpp +++ b/source/training_mods.hpp @@ -2,18 +2,18 @@ #define TRAINING_MODS_H #ifndef M_PI - #define M_PI 3.14159265358979323846 +#define M_PI 3.14159265358979323846 #endif -#include "useful/useful.h" -#include "useful/crc32.h" #include "useful/const_value_table.h" +#include "useful/crc32.h" +#include "useful/useful.h" #include "useful/raygun_printer.hpp" +#include "acmd_wrapper.hpp" #include "imports/lib/l2c.hpp" #include "saltysd/saltysd_dynamic.h" #include "saltysd/saltysd_helper.hpp" -#include "acmd_wrapper.hpp" #include "taunt_toggles.h" using namespace lib; @@ -23,357 +23,385 @@ using namespace app::sv_animcmd; u64 fighter_manager_addr; bool is_operation_cpu(u64 module_accessor) { - int entry_id = WorkModule::get_int(module_accessor, FIGHTER_INSTANCE_WORK_ID_INT_ENTRY_ID); - u64 fighter_information = FighterManager::get_fighter_information(LOAD64(fighter_manager_addr), entry_id); + int entry_id = WorkModule::get_int(module_accessor, + FIGHTER_INSTANCE_WORK_ID_INT_ENTRY_ID); + u64 fighter_information = FighterManager::get_fighter_information( + LOAD64(fighter_manager_addr), entry_id); - return FighterInformation::is_operation_cpu(fighter_information); + return FighterInformation::is_operation_cpu(fighter_information); } bool is_in_hitstun(u64 module_accessor) { - int status_kind = StatusModule::status_kind(module_accessor); - return status_kind >= FIGHTER_STATUS_KIND_DAMAGE && status_kind <= FIGHTER_STATUS_KIND_DAMAGE_FALL; + int status_kind = StatusModule::status_kind(module_accessor); + return status_kind >= FIGHTER_STATUS_KIND_DAMAGE && + status_kind <= FIGHTER_STATUS_KIND_DAMAGE_FALL; } namespace app::lua_bind { - namespace WorkModule { - // Force DI - float get_float_replace(u64 module_accessor, int var) { - // call original WorkModule::get_float_impl - u64 work_module = load_module(module_accessor, 0x50); - float (*get_float)(u64, int) = - (float (*)(u64, int))(load_module_impl(work_module, 0x58)); +namespace WorkModule { +// Force DI +float get_float_replace(u64 module_accessor, int var) { + // call original WorkModule::get_float_impl + u64 work_module = load_module(module_accessor, 0x50); + float (*get_float)(u64, int) = + (float (*)(u64, int))(load_module_impl(work_module, 0x58)); - float ret_val = get_float(work_module, var); + float ret_val = get_float(work_module, var); - if (var == FIGHTER_STATUS_DAMAGE_WORK_FLOAT_VECOR_CORRECT_STICK_X || var == FIGHTER_STATUS_DAMAGE_WORK_FLOAT_VECOR_CORRECT_STICK_Y) { - if (is_training_mode() && is_operation_cpu(module_accessor) && is_in_hitstun(module_accessor)) { - if (DI_STATE != NONE) { - float angle = (DI_STATE - 1) * M_PI / 4.0; + if (var == FIGHTER_STATUS_DAMAGE_WORK_FLOAT_VECOR_CORRECT_STICK_X || + var == FIGHTER_STATUS_DAMAGE_WORK_FLOAT_VECOR_CORRECT_STICK_Y) { + if (is_training_mode() && is_operation_cpu(module_accessor) && + is_in_hitstun(module_accessor)) { + if (DI_STATE != NONE) { + float angle = (DI_STATE - 1) * M_PI / 4.0; - // Either 0 (right) or PI (left) - if (DI_STATE == DI_RANDOM_IN_AWAY) { - angle = app::sv_math::rand(hash40("fighter"), 2) * M_PI; - } - // If facing left, reverse angle - if (PostureModule::lr(module_accessor) != -1.0) angle -= M_PI; + // Either 0 (right) or PI (left) + if (DI_STATE == DI_RANDOM_IN_AWAY) { + angle = app::sv_math::rand(hash40("fighter"), 2) * M_PI; + } + // If facing left, reverse angle + if (PostureModule::lr(module_accessor) != -1.0) angle -= M_PI; - if (var == FIGHTER_STATUS_DAMAGE_WORK_FLOAT_VECOR_CORRECT_STICK_X) - return cos(angle); + if (var == FIGHTER_STATUS_DAMAGE_WORK_FLOAT_VECOR_CORRECT_STICK_X) + return cos(angle); - if (var == FIGHTER_STATUS_DAMAGE_WORK_FLOAT_VECOR_CORRECT_STICK_Y) - return sin(angle); - } - } - } - - return ret_val; - } + if (var == FIGHTER_STATUS_DAMAGE_WORK_FLOAT_VECOR_CORRECT_STICK_Y) + return sin(angle); + } + } + } - float get_param_float_replace(u64 module_accessor, u64 param_type, u64 param_hash) { - if (is_training_mode()) { - if (TOGGLE_STATE == INFINITE_SHIELD) { - if (param_type == hash40("common")) { - if (param_hash == hash40("shield_dec1")) return 0.0; - if (param_hash == hash40("shield_recovery1")) return 999.0; - // doesn't work, somehow. This parameter isn't checked? - if (param_hash == hash40("shield_damage_mul")) return 0.0; - } - } - } + return ret_val; +} - // call original - u64 work_module = load_module(module_accessor, 0x50); - float (*get_param_float)(u64, u64, u64) = - (float (*)(u64, u64, u64))(load_module_impl(work_module, 0x240)); +float get_param_float_replace(u64 module_accessor, u64 param_type, + u64 param_hash) { + if (is_training_mode()) { + if (TOGGLE_STATE == INFINITE_SHIELD) { + if (param_type == hash40("common")) { + if (param_hash == hash40("shield_dec1")) return 0.0; + if (param_hash == hash40("shield_recovery1")) return 999.0; + // doesn't work, somehow. This parameter isn't checked? + if (param_hash == hash40("shield_damage_mul")) return 0.0; + } + } + } - return get_param_float(work_module, param_type, param_hash); - } + // call original + u64 work_module = load_module(module_accessor, 0x50); + float (*get_param_float)(u64, u64, u64) = + (float (*)(u64, u64, u64))(load_module_impl(work_module, 0x240)); - // Force ledge option - u64 enable_transition_term_replace(u64 module_accessor, int transition_id) { - if (TOGGLE_STATE == LEDGE_OPTION && is_training_mode() && is_operation_cpu(module_accessor)) { - if (StatusModule::status_kind(module_accessor) == FIGHTER_STATUS_KIND_CLIFF_WAIT) { - if (transition_id == FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_CLIFF_CLIMB) { - int status = 0; - int ledge_case = LEDGE_STATE; - - if (LEDGE_STATE == RANDOM_LEDGE) - ledge_case = app::sv_math::rand(hash40("fighter"), 4) + 1; + return get_param_float(work_module, param_type, param_hash); +} - switch (ledge_case) { - case NEUTRAL_LEDGE: - status = FIGHTER_STATUS_KIND_CLIFF_CLIMB; break; - case ROLL_LEDGE: - status = FIGHTER_STATUS_KIND_CLIFF_ESCAPE; break; - case JUMP_LEDGE: - status = FIGHTER_STATUS_KIND_CLIFF_JUMP1; break; - case ATTACK_LEDGE: - status = FIGHTER_STATUS_KIND_CLIFF_ATTACK; break; - } - - StatusModule::change_status_request_from_script(module_accessor, status, 1); - } - } - } +// Force ledge option +u64 enable_transition_term_replace(u64 module_accessor, int transition_id) { + if (TOGGLE_STATE == LEDGE_OPTION && is_training_mode() && + is_operation_cpu(module_accessor)) { + if (StatusModule::status_kind(module_accessor) == FIGHTER_STATUS_KIND_CLIFF_WAIT) { + if (transition_id == FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_CLIFF_CLIMB) { + int status = 0; + int ledge_case = LEDGE_STATE; - // call original WorkModule::enable_transition_term_group_impl - u64 work_module = load_module(module_accessor, 0x50); - u64 (*enable_transition_term)(u64, int) = - (u64(*)(u64, int))(load_module_impl(work_module, 0x188)); + if (LEDGE_STATE == RANDOM_LEDGE) + ledge_case = app::sv_math::rand(hash40("fighter"), 4) + 1; - return enable_transition_term(work_module, transition_id); - } - } // namespace WorkModule + switch (ledge_case) { + case NEUTRAL_LEDGE: + status = FIGHTER_STATUS_KIND_CLIFF_CLIMB; break; + case ROLL_LEDGE: + status = FIGHTER_STATUS_KIND_CLIFF_ESCAPE; break; + case JUMP_LEDGE: + status = FIGHTER_STATUS_KIND_CLIFF_JUMP1; break; + case ATTACK_LEDGE: + status = FIGHTER_STATUS_KIND_CLIFF_ATTACK; break; + } - namespace ControlModule { - int get_command_flag_cat_replace(u64 module_accessor, int category) { - // call original - u64 control_module = load_module(module_accessor, 0x48); - int (*get_command_flag_cat)(u64, int) = - (int (*)(u64, int))load_module_impl(control_module, 0x350); - int flag = get_command_flag_cat(control_module, category); + StatusModule::change_status_request_from_script(module_accessor, status, 1); + } + } + } - if (is_training_mode() && is_operation_cpu(module_accessor)) { - if (is_in_hitstun(module_accessor)) { - if (TOGGLE_STATE == MASH_AIRDODGE) - if (category == FIGHTER_PAD_COMMAND_CATEGORY1) - flag |= FIGHTER_PAD_CMD_CAT1_FLAG_AIR_ESCAPE; + // call original WorkModule::enable_transition_term_group_impl + u64 work_module = load_module(module_accessor, 0x50); + u64 (*enable_transition_term)(u64, int) = + (u64(*)(u64, int))(load_module_impl(work_module, 0x188)); - if (TOGGLE_STATE == MASH_JUMP) - if (category == FIGHTER_PAD_COMMAND_CATEGORY1) - flag |= FIGHTER_PAD_CMD_CAT1_FLAG_JUMP_BUTTON; + return enable_transition_term(work_module, transition_id); +} +} // namespace WorkModule - if (TOGGLE_STATE == MASH_ATTACK) - if (category == FIGHTER_PAD_COMMAND_CATEGORY1) { - switch (ATTACK_STATE) { - case MASH_NAIR: - flag |= lua_const("FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_AIR_N"); break; - case MASH_FAIR: - flag |= lua_const("FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_AIR_F"); break; - case MASH_BAIR: - flag |= lua_const("FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_AIR_B"); break; - case MASH_UPAIR: - flag |= lua_const("FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_AIR_HI"); break; - case MASH_DAIR: - flag |= lua_const("FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_AIR_LW"); break; - case MASH_NEUTRAL_B: - flag |= FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_N; break; - case MASH_SIDE_B: - flag |= FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_S; break; - case MASH_UP_B: - flag |= FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_HI; break; - case MASH_DOWN_B: - flag |= FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_LW; break; - } - } +namespace ControlModule { +int get_command_flag_cat_replace(u64 module_accessor, int category) { + // call original + u64 control_module = load_module(module_accessor, 0x48); + int (*get_command_flag_cat)(u64, int) = + (int (*)(u64, int))load_module_impl(control_module, 0x350); + int flag = get_command_flag_cat(control_module, category); - if (TOGGLE_STATE == MASH_RANDOM) - if (category == FIGHTER_PAD_COMMAND_CATEGORY1) { - int random_commands[] = { - FIGHTER_PAD_CMD_CAT1_FLAG_AIR_ESCAPE, - FIGHTER_PAD_CMD_CAT1_FLAG_JUMP_BUTTON, - lua_const("FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_AIR_N"), - lua_const("FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_AIR_F"), - lua_const("FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_AIR_B"), - lua_const("FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_AIR_HI"), - lua_const("FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_AIR_LW"), - FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_N, - FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_S, - FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_HI, - FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_LW, - }; + if (is_training_mode() && is_operation_cpu(module_accessor)) { + if (is_in_hitstun(module_accessor)) { + if (TOGGLE_STATE == MASH_AIRDODGE) + if (category == FIGHTER_PAD_COMMAND_CATEGORY1) + flag |= FIGHTER_PAD_CMD_CAT1_FLAG_AIR_ESCAPE; - int random_cmd_index = app::sv_math::rand(hash40("fighter"), 11); + if (TOGGLE_STATE == MASH_JUMP) + if (category == FIGHTER_PAD_COMMAND_CATEGORY1) + flag |= FIGHTER_PAD_CMD_CAT1_FLAG_JUMP_BUTTON; - flag |= random_commands[random_cmd_index]; - } - } - } + if (TOGGLE_STATE == MASH_ATTACK) + if (category == FIGHTER_PAD_COMMAND_CATEGORY1) { + switch (ATTACK_STATE) { + case MASH_NAIR: + flag |= lua_const("FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_AIR_N"); break; + case MASH_FAIR: + flag |= lua_const("FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_AIR_F"); break; + case MASH_BAIR: + flag |= lua_const("FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_AIR_B"); break; + case MASH_UPAIR: + flag |= lua_const("FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_AIR_HI"); break; + case MASH_DAIR: + flag |= lua_const("FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_AIR_LW"); break; + case MASH_NEUTRAL_B: + flag |= FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_N; break; + case MASH_SIDE_B: + flag |= FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_S; break; + case MASH_UP_B: + flag |= FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_HI; break; + case MASH_DOWN_B: + flag |= FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_LW; break; + } + } - return flag; - } + if (TOGGLE_STATE == MASH_RANDOM) + if (category == FIGHTER_PAD_COMMAND_CATEGORY1) { + int random_commands[] = { + FIGHTER_PAD_CMD_CAT1_FLAG_AIR_ESCAPE, + FIGHTER_PAD_CMD_CAT1_FLAG_JUMP_BUTTON, + lua_const("FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_AIR_N"), + lua_const("FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_AIR_F"), + lua_const("FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_AIR_B"), + lua_const("FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_AIR_HI"), + lua_const("FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_AIR_LW"), + FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_N, + FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_S, + FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_HI, + FIGHTER_PAD_CMD_CAT1_FLAG_SPECIAL_LW, + }; - bool check_button_on_replace(u64 module_accessor, int button) { - if (button == CONTROL_PAD_BUTTON_GUARD_HOLD || - button == CONTROL_PAD_BUTTON_GUARD) { - if (is_training_mode() && is_operation_cpu(module_accessor)) { - if (TOGGLE_STATE == HOLD_SHIELD || TOGGLE_STATE == INFINITE_SHIELD) - return true; - if (TOGGLE_STATE == MASH_AIRDODGE && is_in_hitstun(module_accessor)) - return true; - } - } + int random_cmd_index = + app::sv_math::rand(hash40("fighter"), 11); - // call original - u64 control_module = load_module(module_accessor, 0x48); - bool (*check_button_on)(u64, int) = - (bool (*)(u64, int))load_module_impl(control_module, 0x260); - return check_button_on(control_module, button); - } + flag |= random_commands[random_cmd_index]; + } + } + } - bool check_button_off_replace(u64 module_accessor, int button) { - if (button == CONTROL_PAD_BUTTON_GUARD_HOLD || - button == CONTROL_PAD_BUTTON_GUARD) { - if (is_training_mode() && is_operation_cpu(module_accessor)) { - if (TOGGLE_STATE == HOLD_SHIELD || TOGGLE_STATE == INFINITE_SHIELD) - return false; - } - } + return flag; +} - // call original - u64 control_module = load_module(module_accessor, 0x48); - bool (*check_button_off)(u64, int) = - (bool (*)(u64, int))load_module_impl(control_module, 0x268); - return check_button_off(control_module, button); - } +bool check_button_on_replace(u64 module_accessor, int button) { + if (button == CONTROL_PAD_BUTTON_GUARD_HOLD || + button == CONTROL_PAD_BUTTON_GUARD) { + if (is_training_mode() && is_operation_cpu(module_accessor)) { + if (TOGGLE_STATE == HOLD_SHIELD || TOGGLE_STATE == INFINITE_SHIELD) + return true; + if (TOGGLE_STATE == MASH_AIRDODGE && is_in_hitstun(module_accessor)) + return true; + } + } - #define SAVE_STATE 1 - #define DEFAULT 2 - #define CAMERA_MOVE 3 - #define POS_MOVE 4 + // call original + u64 control_module = load_module(module_accessor, 0x48); + bool (*check_button_on)(u64, int) = + (bool (*)(u64, int))load_module_impl(control_module, 0x260); + return check_button_on(control_module, button); +} - int save_state_player_state = DEFAULT; - int save_state_cpu_state = DEFAULT; - bool save_state_move_alert = false; +bool check_button_off_replace(u64 module_accessor, int button) { + if (button == CONTROL_PAD_BUTTON_GUARD_HOLD || + button == CONTROL_PAD_BUTTON_GUARD) { + if (is_training_mode() && is_operation_cpu(module_accessor)) { + if (TOGGLE_STATE == HOLD_SHIELD || TOGGLE_STATE == INFINITE_SHIELD) + return false; + } + } - float save_state_x_player = 0; - float save_state_y_player = 0; - float save_state_percent_player = 0; - float save_state_lr_player = 1.0; - int save_state_situation_kind_player = 0; + // call original + u64 control_module = load_module(module_accessor, 0x48); + bool (*check_button_off)(u64, int) = + (bool (*)(u64, int))load_module_impl(control_module, 0x268); + return check_button_off(control_module, button); +} - float save_state_x_cpu = 0; - float save_state_y_cpu = 0; - float save_state_percent_cpu = 0; - float save_state_lr_cpu = 1.0; - int save_state_situation_kind_cpu = 0; +#define SAVE_STATE 1 +#define DEFAULT 2 +#define CAMERA_MOVE 3 +#define POS_MOVE 4 - int get_pad_flag_replace(u64 module_accessor) { - if (is_training_mode()) { - float* save_state_x; - float* save_state_y; - float* save_state_percent; - float* save_state_lr; - int* save_state_situation_kind; - int* save_state; - if (is_operation_cpu(module_accessor)) { - save_state_x = &save_state_x_cpu; - save_state_y = &save_state_y_cpu; - save_state_percent = &save_state_percent_cpu; - save_state_lr = &save_state_lr_cpu; - save_state_situation_kind = &save_state_situation_kind_cpu; - save_state = &save_state_cpu_state; - } else { - save_state_x = &save_state_x_player; - save_state_y = &save_state_y_player; - save_state_percent = &save_state_percent_player; - save_state_lr = &save_state_lr_player; - save_state_situation_kind = &save_state_situation_kind_player; - save_state = &save_state_player_state; - } +int save_state_player_state = DEFAULT; +int save_state_cpu_state = DEFAULT; +bool save_state_move_alert = false; - // Grab + Dpad up: reset state - if (ControlModule::check_button_on(module_accessor, CONTROL_PAD_BUTTON_CATCH) && - ControlModule::check_button_trigger(module_accessor, CONTROL_PAD_BUTTON_APPEAL_HI)) { - if (*save_state == DEFAULT) { - save_state_player_state = CAMERA_MOVE; - save_state_cpu_state = CAMERA_MOVE; - } - } +float save_state_x_player = 0; +float save_state_y_player = 0; +float save_state_percent_player = 0; +float save_state_lr_player = 1.0; +int save_state_situation_kind_player = 0; - // move to camera bounds - if (*save_state == CAMERA_MOVE) { - *save_state = POS_MOVE; +float save_state_x_cpu = 0; +float save_state_y_cpu = 0; +float save_state_percent_cpu = 0; +float save_state_lr_cpu = 1.0; +int save_state_situation_kind_cpu = 0; - float left_right = (*save_state_x > 0) - (*save_state_x < 0); - float y_pos = 0; - if (*save_state_situation_kind == SITUATION_KIND_GROUND) y_pos = -50; +int get_pad_flag_replace(u64 module_accessor) { + if (is_training_mode()) { + float* save_state_x; + float* save_state_y; + float* save_state_percent; + float* save_state_lr; + int* save_state_situation_kind; + int* save_state; + if (is_operation_cpu(module_accessor)) { + save_state_x = &save_state_x_cpu; + save_state_y = &save_state_y_cpu; + save_state_percent = &save_state_percent_cpu; + save_state_lr = &save_state_lr_cpu; + save_state_situation_kind = &save_state_situation_kind_cpu; + save_state = &save_state_cpu_state; + } else { + save_state_x = &save_state_x_player; + save_state_y = &save_state_y_player; + save_state_percent = &save_state_percent_player; + save_state_lr = &save_state_lr_player; + save_state_situation_kind = &save_state_situation_kind_player; + save_state = &save_state_player_state; + } - Vector3f pos = {.x = left_right * 50, .y = y_pos, .z = 0}; - PostureModule::set_pos(module_accessor, &pos); - StatusModule::set_situation_kind(module_accessor, SITUATION_KIND_AIR, 0); - } + // Grab + Dpad up: reset state + if (ControlModule::check_button_on(module_accessor, + CONTROL_PAD_BUTTON_CATCH) && + ControlModule::check_button_trigger(module_accessor, + CONTROL_PAD_BUTTON_APPEAL_HI)) { + if (*save_state == DEFAULT) { + save_state_player_state = CAMERA_MOVE; + save_state_cpu_state = CAMERA_MOVE; + } + } - // move to correct pos - if (*save_state == POS_MOVE) { - *save_state = DEFAULT; + // move to camera bounds + if (*save_state == CAMERA_MOVE) { + *save_state = POS_MOVE; - Vector3f pos = {.x = *save_state_x, .y = *save_state_y, .z = 0}; - PostureModule::set_pos(module_accessor, &pos); - PostureModule::set_lr(module_accessor, *save_state_lr); - DamageModule::add_damage(module_accessor, -1.0 * DamageModule::damage(module_accessor, 0), 0); - DamageModule::add_damage(module_accessor, *save_state_percent, 0); - StatusModule::set_situation_kind(module_accessor, *save_state_situation_kind, 0); + float left_right = (*save_state_x > 0) - (*save_state_x < 0); + float y_pos = 0; + if (*save_state_situation_kind == SITUATION_KIND_GROUND) + y_pos = -50; - // Doesn't work, and I don't know why yet. - /*if (*save_state_situation_kind == SITUATION_KIND_GROUND) - StatusModule::change_status_request(module_accessor, FIGHTER_STATUS_KIND_WAIT, 0); - else if (*save_state_situation_kind == SITUATION_KIND_AIR) - StatusModule::change_status_request(module_accessor, FIGHTER_STATUS_KIND_FALL, 0); - else if (*save_state_situation_kind == SITUATION_KIND_CLIFF) - StatusModule::change_status_request(module_accessor, FIGHTER_STATUS_KIND_CLIFF_CATCH, 0); - */ - } + Vector3f pos = {.x = left_right * 50, .y = y_pos, .z = 0}; + PostureModule::set_pos(module_accessor, &pos); + StatusModule::set_situation_kind(module_accessor, + SITUATION_KIND_AIR, 0); + } - // Grab + Dpad down: Save state - if (ControlModule::check_button_on(module_accessor, CONTROL_PAD_BUTTON_CATCH) && - ControlModule::check_button_trigger(module_accessor, CONTROL_PAD_BUTTON_APPEAL_LW)) { - save_state_player_state = SAVE_STATE; - save_state_cpu_state = SAVE_STATE; - } + // move to correct pos + if (*save_state == POS_MOVE) { + *save_state = DEFAULT; - if (*save_state == SAVE_STATE) { - *save_state = DEFAULT; + Vector3f pos = {.x = *save_state_x, .y = *save_state_y, .z = 0}; + PostureModule::set_pos(module_accessor, &pos); + PostureModule::set_lr(module_accessor, *save_state_lr); + DamageModule::add_damage( + module_accessor, + -1.0 * DamageModule::damage(module_accessor, 0), 0); + DamageModule::add_damage(module_accessor, *save_state_percent, 0); + StatusModule::set_situation_kind(module_accessor, + *save_state_situation_kind, 0); - *save_state_x = PostureModule::pos_x(module_accessor); - *save_state_y = PostureModule::pos_y(module_accessor); - *save_state_lr = PostureModule::lr(module_accessor); - *save_state_percent = DamageModule::damage(module_accessor, 0); - *save_state_situation_kind = StatusModule::situation_kind(module_accessor); - } - } + // Doesn't work, and I don't know why yet. + /*if (*save_state_situation_kind == SITUATION_KIND_GROUND) + StatusModule::change_status_request(module_accessor, + FIGHTER_STATUS_KIND_WAIT, 0); else if (*save_state_situation_kind == + SITUATION_KIND_AIR) + StatusModule::change_status_request(module_accessor, + FIGHTER_STATUS_KIND_FALL, 0); else if (*save_state_situation_kind == + SITUATION_KIND_CLIFF) + StatusModule::change_status_request(module_accessor, + FIGHTER_STATUS_KIND_CLIFF_CATCH, 0); + */ + } - // call original - u64 control_module = load_module(module_accessor, 0x48); - int (*get_pad_flag)(u64) = - (int (*)(u64))load_module_impl(control_module, 0x348); - return get_pad_flag(control_module); - } - } // namespace ControlModule + // Grab + Dpad down: Save state + if (ControlModule::check_button_on(module_accessor, + CONTROL_PAD_BUTTON_CATCH) && + ControlModule::check_button_trigger(module_accessor, + CONTROL_PAD_BUTTON_APPEAL_LW)) { + save_state_player_state = SAVE_STATE; + save_state_cpu_state = SAVE_STATE; + } + + if (*save_state == SAVE_STATE) { + *save_state = DEFAULT; + + *save_state_x = PostureModule::pos_x(module_accessor); + *save_state_y = PostureModule::pos_y(module_accessor); + *save_state_lr = PostureModule::lr(module_accessor); + *save_state_percent = DamageModule::damage(module_accessor, 0); + *save_state_situation_kind = + StatusModule::situation_kind(module_accessor); + } + } + + // call original + u64 control_module = load_module(module_accessor, 0x48); + int (*get_pad_flag)(u64) = + (int (*)(u64))load_module_impl(control_module, 0x348); + return get_pad_flag(control_module); +} +} // namespace ControlModule } // namespace app::lua_bind void training_mods_main() { - fighter_manager_addr = SaltySDCore_FindSymbol("_ZN3lib9SingletonIN3app14FighterManagerEE9instance_E"); - // Mash airdodge/jump - SaltySD_function_replace_sym( - "_ZN3app8lua_bind40ControlModule__get_command_flag_cat_implEPNS_26BattleObjectModuleAccessorEi", - (u64)&ControlModule::get_command_flag_cat_replace); - - // Set DI - SaltySD_function_replace_sym( - "_ZN3app8lua_bind26WorkModule__get_float_implEPNS_26BattleObjectModuleAccessorEi", - (u64)&WorkModule::get_float_replace); + fighter_manager_addr = SaltySDCore_FindSymbol( + "_ZN3lib9SingletonIN3app14FighterManagerEE9instance_E"); + // Mash airdodge/jump + SaltySD_function_replace_sym( + "_ZN3app8lua_bind40ControlModule__get_command_flag_cat_implEPNS_" + "26BattleObjectModuleAccessorEi", + (u64)&ControlModule::get_command_flag_cat_replace); - // Hold/Infinite shield - SaltySD_function_replace_sym( - "_ZN3app8lua_bind35ControlModule__check_button_on_implEPNS_26BattleObjectModuleAccessorEi", - (u64)&ControlModule::check_button_on_replace); - SaltySD_function_replace_sym( - "_ZN3app8lua_bind36ControlModule__check_button_off_implEPNS_26BattleObjectModuleAccessorEi", - (u64)&ControlModule::check_button_off_replace); - SaltySD_function_replace_sym( - "_ZN3app8lua_bind32WorkModule__get_param_float_implEPNS_26BattleObjectModuleAccessorEmm", - (u64)&WorkModule::get_param_float_replace); + // Set DI + SaltySD_function_replace_sym( + "_ZN3app8lua_bind26WorkModule__get_float_implEPNS_" + "26BattleObjectModuleAccessorEi", + (u64)&WorkModule::get_float_replace); - // Ledge options - SaltySD_function_replace_sym( - "_ZN3app8lua_bind39WorkModule__enable_transition_term_implEPNS_26BattleObjectModuleAccessorEi", - (u64)&WorkModule::enable_transition_term_replace); + // Hold/Infinite shield + SaltySD_function_replace_sym( + "_ZN3app8lua_bind35ControlModule__check_button_on_implEPNS_" + "26BattleObjectModuleAccessorEi", + (u64)&ControlModule::check_button_on_replace); + SaltySD_function_replace_sym( + "_ZN3app8lua_bind36ControlModule__check_button_off_implEPNS_" + "26BattleObjectModuleAccessorEi", + (u64)&ControlModule::check_button_off_replace); + SaltySD_function_replace_sym( + "_ZN3app8lua_bind32WorkModule__get_param_float_implEPNS_" + "26BattleObjectModuleAccessorEmm", + (u64)&WorkModule::get_param_float_replace); - // Save states: in beta - /*SaltySD_function_replace_sym( - "_ZN3app8lua_bind32ControlModule__get_pad_flag_implEPNS_26BattleObjectModuleAccessorE", - (u64)&ControlModule::get_pad_flag_replace);*/ + // Ledge options + SaltySD_function_replace_sym( + "_ZN3app8lua_bind39WorkModule__enable_transition_term_implEPNS_" + "26BattleObjectModuleAccessorEi", + (u64)&WorkModule::enable_transition_term_replace); + + // Save states: in beta + /*SaltySD_function_replace_sym( + "_ZN3app8lua_bind32ControlModule__get_pad_flag_implEPNS_26BattleObjectModuleAccessorE", + (u64)&ControlModule::get_pad_flag_replace);*/ } -#endif // TRAINING_MODS_H +#endif // TRAINING_MODS_H diff --git a/source/useful/raygun_printer.hpp b/source/useful/raygun_printer.hpp index 50f015f..a90a9e5 100644 --- a/source/useful/raygun_printer.hpp +++ b/source/useful/raygun_printer.hpp @@ -1,8 +1,8 @@ #ifndef RAYGUN_PRINTER_H #define RAYGUN_PRINTER_H -#include <switch.h> #include <ctype.h> +#include <switch.h> #include "useful.h" @@ -18,106 +18,62 @@ using namespace app::lua_bind; segment data list : {Z, Y, X, ZRot, Size} segment labels : _ - |_| from top to top left, clockwise: a->f + g mid + \|/ from top mid to top left, clockwise: h->m + --two half g's: n, o + |_| from top to top left, clockwise: a->f + g mid + \|/ from top mid to + top left, clockwise: h->m + --two half g's: n, o |_| /|\ */ const float segment_dict[15][5] = { - {0, RAYGUN_HEIGHT*2, 0, 0, 0.25}, // a - {0, RAYGUN_HEIGHT, RAYGUN_LENGTH, 90, 0.25}, // b - {0, 0, RAYGUN_LENGTH, 90, 0.25}, // c - {0, 0, 0, 0, 0.25}, // d - {0, 0, 0, 90, 0.25}, // e - {0, RAYGUN_HEIGHT, 0, 90, 0.25}, // f - {0, RAYGUN_HEIGHT, 0, 0, 0.25}, // g mid - {0, RAYGUN_HEIGHT, RAYGUN_LENGTH/2, 90, 0.25}, // h - {0, RAYGUN_HEIGHT, RAYGUN_LENGTH/2, 52, 0.2}, // i - {0, RAYGUN_HEIGHT, RAYGUN_LENGTH/2, -52, 0.2}, // j - {0, 0, RAYGUN_LENGTH/2, 90, 0.25}, // k - {0, RAYGUN_HEIGHT/2, RAYGUN_LENGTH*3/16, 52, 0.2}, // l - {0, RAYGUN_HEIGHT*3/2, RAYGUN_LENGTH*3/16, -52, 0.2}, // m - {0, RAYGUN_HEIGHT, 0, 0, 0.15}, // n - {0, RAYGUN_HEIGHT, RAYGUN_LENGTH/2, 0, 0.15}, // o - }; + {0, RAYGUN_HEIGHT * 2, 0, 0, 0.25}, // a + {0, RAYGUN_HEIGHT, RAYGUN_LENGTH, 90, 0.25}, // b + {0, 0, RAYGUN_LENGTH, 90, 0.25}, // c + {0, 0, 0, 0, 0.25}, // d + {0, 0, 0, 90, 0.25}, // e + {0, RAYGUN_HEIGHT, 0, 90, 0.25}, // f + {0, RAYGUN_HEIGHT, 0, 0, 0.25}, // g mid + {0, RAYGUN_HEIGHT, RAYGUN_LENGTH / 2, 90, 0.25}, // h + {0, RAYGUN_HEIGHT, RAYGUN_LENGTH / 2, 52, 0.2}, // i + {0, RAYGUN_HEIGHT, RAYGUN_LENGTH / 2, -52, 0.2}, // j + {0, 0, RAYGUN_LENGTH / 2, 90, 0.25}, // k + {0, RAYGUN_HEIGHT / 2, RAYGUN_LENGTH * 3 / 16, 52, 0.2}, // l + {0, RAYGUN_HEIGHT * 3 / 2, RAYGUN_LENGTH * 3 / 16, -52, 0.2}, // m + {0, RAYGUN_HEIGHT, 0, 0, 0.15}, // n + {0, RAYGUN_HEIGHT, RAYGUN_LENGTH / 2, 0, 0.15}, // o +}; -/* +/* Segments making up each character, each index corresponding to: - 'A' through 'Z', '0' through '9', ' ', '-', '+', '#' (where '#' is all segments) + 'A' through 'Z', '0' through '9', ' ', '-', '+', '#' (where '#' is all + segments) */ -const char* alphabet[] = { - "abcefg", - "adefijn", - "adef", - "eflm", - "adefn", - "aefn", - "acdefo", - "bcefg", - "adhk", - "bcd", - "efnij", - "def", - "bcefim", - "bcefjm", - "abcdef", - "abefg", - "abcdefj", - "aefijn", - "acdfg", - "ahk", - "bcdef", - "efil", - "bcefjl", - "ijlm", - "ikm", - "adil", - "abcdef", - "ef", - "abdeg", - "abcdg", - "bcfg", - "acdfg", - "acdefg", - "abc", - "abcdefg", - "abcdfg", - "", - "g", - "ghk", - "abcdefhijklmno", +const char* alphabet[] = { + "abcefg", "adefijn", "adef", "eflm", "adefn", + "aefn", "acdefo", "bcefg", "adhk", "bcd", + "efnij", "def", "bcefim", "bcefjm", "abcdef", + "abefg", "abcdefj", "aefijn", "acdfg", "ahk", + "bcdef", "efil", "bcefjl", "ijlm", "ikm", + "adil", "abcdef", "ef", "abdeg", "abcdg", + "bcfg", "acdfg", "acdefg", "abc", "abcdefg", + "abcdfg", "", "g", "ghk", "abcdefhijklmno", }; // Each index is a segment's corresponding flipped segment, for when facing left const char segment_rev[15] = { - 'a', - 'f', - 'e', - 'd', - 'c', - 'b', - 'g', - 'h', - 'm', - 'l', - 'k', - 'j', - 'i', - 'o', - 'n', + 'a', 'f', 'e', 'd', 'c', 'b', 'g', 'h', 'm', 'l', 'k', 'j', 'i', 'o', 'n', }; -void show_segment(u64 battle_object_module_accessor, float z, float y, float x, float zrot, float size) { - Hash40 raygunShot = { .hash = 0x11e470b07fLL }; - Hash40 top = { .hash = 0x031ed91fcaLL }; +void show_segment(u64 battle_object_module_accessor, float z, float y, float x, + float zrot, float size) { + Hash40 raygunShot = {.hash = 0x11e470b07fLL}; + Hash40 top = {.hash = 0x031ed91fcaLL}; - Vector3f pos = { .x = x, .y = y, .z = z }; - Vector3f rot = { .x = 0, .y = 90, .z = zrot }; - Vector3f random = { .x = 0, .y = 0, .z = 0 }; + Vector3f pos = {.x = x, .y = y, .z = z}; + Vector3f rot = {.x = 0, .y = 90, .z = zrot}; + Vector3f random = {.x = 0, .y = 0, .z = 0}; - EffectModule::req_on_joint(battle_object_module_accessor, raygunShot.hash, top.hash, - &pos, &rot, size, - &random, &random, - 0, 0, 0, 0); + EffectModule::req_on_joint(battle_object_module_accessor, raygunShot.hash, + top.hash, &pos, &rot, size, &random, &random, 0, + 0, 0, 0); } int alphabet_index(char to_print) { @@ -137,10 +93,10 @@ int alphabet_index(char to_print) { return -1; } -void print_char( u64 module_accessor, char to_print, int line_num, float horiz_offset, float facing_left) { +void print_char(u64 module_accessor, char to_print, int line_num, + float horiz_offset, float facing_left) { int alph_index = alphabet_index(to_print); - if (alph_index < 0 || alph_index >= 40) - return; + if (alph_index < 0 || alph_index >= 40) return; const char* segment_str = alphabet[alph_index]; int num_segments = strlen(segment_str); @@ -152,7 +108,7 @@ void print_char( u64 module_accessor, char to_print, int line_num, float horiz_o if (facing_left == -1) { index = segment_rev[index] - 'a'; - } + } segment = segment_dict[index]; float z = segment[0]; @@ -160,17 +116,16 @@ void print_char( u64 module_accessor, char to_print, int line_num, float horiz_o float x = segment[2] + horiz_offset; float zrot = segment[3]; - if (facing_left == -1) - zrot *= -1; + if (facing_left == -1) zrot *= -1; float size = segment[4]; show_segment(module_accessor, z, y, x, zrot, size); } } -void print_string( u64 module_accessor, const char* print_str) { +void print_string(u64 module_accessor, const char* print_str) { // Delete any previous strings - Hash40 raygunShot = { .hash = 0x11e470b07fLL }; + Hash40 raygunShot = {.hash = 0x11e470b07fLL}; EffectModule::kill_kind(module_accessor, raygunShot.hash, 0, 1); int line_num = 0; @@ -181,7 +136,7 @@ void print_string( u64 module_accessor, const char* print_str) { if (strlen(print_str) <= 8 && strchr(print_str, '\n') == NULL) { line_num = 1; - } + } horiz_offset = 0; char_num = 0; for (size_t i = 0; i < strlen(print_str); i++) { @@ -193,15 +148,16 @@ void print_string( u64 module_accessor, const char* print_str) { continue; } - print_char(module_accessor, toupper(curr_char), line_num, horiz_offset, facing_left); + print_char(module_accessor, toupper(curr_char), line_num, horiz_offset, + facing_left); char_num++; // short characters if (curr_char == 'D' || curr_char == '1') { - horiz_offset += facing_left * (RAYGUN_LENGTH/2 + 3); + horiz_offset += facing_left * (RAYGUN_LENGTH / 2 + 3); } else { horiz_offset += facing_left * (RAYGUN_LENGTH + 3); - } + } if (char_num > 8) { horiz_offset = 0; @@ -211,4 +167,4 @@ void print_string( u64 module_accessor, const char* print_str) { } } -#endif // RAYGUN_PRINTER_H +#endif // RAYGUN_PRINTER_H diff --git a/source/useful/visual.h b/source/useful/visual.h index 1fa51ea..41701d9 100644 --- a/source/useful/visual.h +++ b/source/useful/visual.h @@ -1,56 +1,63 @@ #ifndef USEFUL_VISUAL_H #define USEFUL_VISUAL_H -#include "useful.h" #include <math.h> +#include "useful.h" /** * Rounds a number to the nearest multiple of another number. */ -float round_to(float val, float align) { - return roundf(val / align) * align; -} +float round_to(float val, float align) { return roundf(val / align) * align; } /** * Linearly interpolates between two numbers, without bounds checking. */ -float lerp(float min, float max, float t) { - return min + (max - min) * t; -} +float lerp(float min, float max, float t) { return min + (max - min) * t; } float unlerp(float min, float max, float val) { - return (val - min) / (max - min); + return (val - min) / (max - min); } /** * Linearly interpolates between two numbers, with bounds checking. */ float lerp_bounded(float min, float max, float t) { - return t <= 0 ? min : t >= 1 ? max : lerp(min, max, t); + return t <= 0 ? min : t >= 1 ? max : lerp(min, max, t); } float unlerp_bounded(float min, float max, float val) { - return val <= min ? 0 : val >= max ? 1 : unlerp(min, max, val); + return val <= min ? 0 : val >= max ? 1 : unlerp(min, max, val); } /** - * Linearly nterpolates between two colors, with bounds checking, accounting for gamma. - * arguments: - * - min_color (Vector3f) -- xyz maps to rgb, components are usually in the range [0.0f, 1.0f] but can go beyond to account for super-bright or super-dark colors + * Linearly nterpolates between two colors, with bounds checking, accounting for + * gamma. arguments: + * - min_color (Vector3f) -- xyz maps to rgb, components are usually in the + * range [0.0f, 1.0f] but can go beyond to account for super-bright or + * super-dark colors * - max_Color (Vector3f) -- same as minColor * - t (float) -- how far to interpolate between the colors - * - gamma (float = 2.0f) -- used for color correction, helps avoid ugly dark colors when interpolating b/t bright colors + * - gamma (float = 2.0f) -- used for color correction, helps avoid ugly dark + * colors when interpolating b/t bright colors */ -Vector3f color_lerp(Vector3f min_color, Vector3f max_color, float t, float gamma = 2.0f) { - float gamma_inv = 1.0f / gamma; - float align = 1.0f / 255.0f; // color components must be a multiple of 1/255 - return { - round_to(powf(lerp_bounded(powf(min_color.x, gamma), powf(max_color.x, gamma), t), gamma_inv), align), - round_to(powf(lerp_bounded(powf(min_color.y, gamma), powf(max_color.y, gamma), t), gamma_inv), align), - round_to(powf(lerp_bounded(powf(min_color.z, gamma), powf(max_color.z, gamma), t), gamma_inv), align) - }; +Vector3f color_lerp(Vector3f min_color, Vector3f max_color, float t, + float gamma = 2.0f) { + float gamma_inv = 1.0f / gamma; + float align = + 1.0f / 255.0f; // color components must be a multiple of 1/255 + return {round_to(powf(lerp_bounded(powf(min_color.x, gamma), + powf(max_color.x, gamma), t), + gamma_inv), + align), + round_to(powf(lerp_bounded(powf(min_color.y, gamma), + powf(max_color.y, gamma), t), + gamma_inv), + align), + round_to(powf(lerp_bounded(powf(min_color.z, gamma), + powf(max_color.z, gamma), t), + gamma_inv), + align)}; } - -#endif // USEFUL_VISUAL_H +#endif // USEFUL_VISUAL_H