mirror of
https://github.com/jugeeya/UltimateTrainingModpack.git
synced 2025-03-14 02:16:10 +00:00
Merge pull request #14 from TheSmartKid/master
Code cleanup and improved hitbox visualization
This commit is contained in:
commit
bf095421ab
23 changed files with 1000 additions and 892 deletions
|
@ -3,17 +3,17 @@
|
|||
|
||||
#include <switch.h>
|
||||
|
||||
namespace app::sv_animcmd
|
||||
{
|
||||
extern void frame(u64, float) asm("_ZN3app10sv_animcmd5frameEP9lua_Statef") LINKABLE;
|
||||
extern void is_excute(u64) asm("_ZN3app10sv_animcmd9is_excuteEP9lua_State") LINKABLE;
|
||||
extern u64 ATTACK(u64) asm("_ZN3app10sv_animcmd6ATTACKEP9lua_State") LINKABLE;
|
||||
extern u64 EFFECT(u64) asm("_ZN3app10sv_animcmd6EFFECTEP9lua_State") LINKABLE;
|
||||
namespace app::sv_animcmd {
|
||||
extern void wait(u64, float) asm("_ZN3app10sv_animcmd4waitEP9lua_Statef") LINKABLE;
|
||||
extern void frame(u64, float) asm("_ZN3app10sv_animcmd5frameEP9lua_Statef") LINKABLE;
|
||||
extern void is_excute(u64) asm("_ZN3app10sv_animcmd9is_excuteEP9lua_State") LINKABLE;
|
||||
extern u64 ATTACK(u64) asm("_ZN3app10sv_animcmd6ATTACKEP9lua_State") LINKABLE;
|
||||
extern u64 CATCH(u64) asm("_ZN3app10sv_animcmd5CATCHEP9lua_State") LINKABLE;
|
||||
|
||||
extern u64 EFFECT(u64) asm("_ZN3app10sv_animcmd6EFFECTEP9lua_State") LINKABLE;
|
||||
extern u64 EFFECT_FOLLOW_NO_SCALE(u64) asm("_ZN3app10sv_animcmd22EFFECT_FOLLOW_NO_SCALEEP9lua_State") LINKABLE;
|
||||
extern u64 LAST_EFFECT_SET_COLOR(u64) asm("_ZN3app10sv_animcmd21LAST_EFFECT_SET_COLOREP9lua_State") LINKABLE;
|
||||
extern u64 LAST_EFFECT_SET_RATE(u64) asm("_ZN3app10sv_animcmd20LAST_EFFECT_SET_RATEEP9lua_State") LINKABLE;
|
||||
extern u64 EFFECT(u64) asm("_ZN3app10sv_animcmd6EFFECTEP9lua_State") LINKABLE;
|
||||
extern u64 EFFECT_FOLLOW_NO_SCALE(u64) asm("_ZN3app10sv_animcmd22EFFECT_FOLLOW_NO_SCALEEP9lua_State") LINKABLE;
|
||||
extern u64 LAST_EFFECT_SET_COLOR(u64) asm("_ZN3app10sv_animcmd21LAST_EFFECT_SET_COLOREP9lua_State") LINKABLE;
|
||||
extern u64 LAST_EFFECT_SET_RATE(u64) asm("_ZN3app10sv_animcmd20LAST_EFFECT_SET_RATEEP9lua_State") LINKABLE;
|
||||
}
|
||||
|
||||
#endif // ACMD_IMPORTS_H
|
||||
#endif // ACMD_IMPORTS_H
|
||||
|
|
|
@ -5,201 +5,229 @@
|
|||
|
||||
#include "acmd_imports.hpp"
|
||||
#include "l2c_imports.hpp"
|
||||
#include "lua_helper.hpp"
|
||||
|
||||
#include <initializer_list>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
namespace app::sv_system
|
||||
{
|
||||
u64 battle_object_module_accessor(u64) asm("_ZN3app9sv_system29battle_object_module_accessorEP9lua_State") LINKABLE;
|
||||
u64 function_impl = LOAD64(module) + function_offset;
|
||||
return (void*) LOAD64(function_impl);
|
||||
}
|
||||
|
||||
namespace app::sv_math {
|
||||
int rand(u64 hash, int endIndex) asm("_ZN3app7sv_math4randEN3phx6Hash40Ei") LINKABLE;
|
||||
int rand(u64, int) asm("_ZN3app7sv_math4randEN3phx6Hash40Ei") LINKABLE;
|
||||
}
|
||||
|
||||
namespace app::lua_bind
|
||||
{
|
||||
namespace AttackModule {
|
||||
void clear_all(u64) asm("_ZN3app8lua_bind28AttackModule__clear_all_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
|
||||
}
|
||||
|
||||
namespace ControlModule {
|
||||
bool check_button_on(u64, int) asm("_ZN3app8lua_bind35ControlModule__check_button_on_implEPNS_26BattleObjectModuleAccessorEi") LINKABLE;
|
||||
}
|
||||
|
||||
namespace EffectModule {
|
||||
// boma, effect, joint, pos, rot, size, random_pos, random_rot, NO_SCALE?, attr?, unkint1, unkint2
|
||||
uint req_on_joint(u64, u64, u64, const Vector3f*, const Vector3f*, float a6, const Vector3f*, const Vector3f*, bool, uint, int, int)
|
||||
asm("_ZN3app8lua_bind31EffectModule__req_on_joint_implEPNS_26BattleObjectModuleAccessorEN3phx6Hash40ES4_RKNS3_8Vector3fES7_fS7_S7_bjii") LINKABLE;
|
||||
|
||||
void kill_kind(u64, u64, bool, bool)
|
||||
asm("_ZN3app8lua_bind28EffectModule__kill_kind_implEPNS_26BattleObjectModuleAccessorEN3phx6Hash40Ebb") LINKABLE;
|
||||
}
|
||||
|
||||
namespace FighterManager {
|
||||
u64 get_fighter_information(u64, int) asm("_ZN3app8lua_bind44FighterManager__get_fighter_information_implEPNS_14FighterManagerENS_14FighterEntryIDE") LINKABLE;
|
||||
}
|
||||
|
||||
namespace FighterInformation {
|
||||
bool is_operation_cpu(u64) asm("_ZN3app8lua_bind41FighterInformation__is_operation_cpu_implEPNS_18FighterInformationE") LINKABLE;
|
||||
}
|
||||
|
||||
namespace MotionModule {
|
||||
float frame(u64) asm("_ZN3app8lua_bind24MotionModule__frame_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
|
||||
u64 motion_kind(u64) asm("_ZN3app8lua_bind30MotionModule__motion_kind_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
|
||||
}
|
||||
|
||||
namespace PostureModule {
|
||||
float lr(u64) asm("_ZN3app8lua_bind22PostureModule__lr_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
|
||||
float pos_x(u64) asm("_ZN3app8lua_bind25PostureModule__pos_x_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
|
||||
float pos_y(u64) asm("_ZN3app8lua_bind25PostureModule__pos_y_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
|
||||
float set_pos(u64, const Vector3f*) asm("_ZN3app8lua_bind27PostureModule__set_pos_implEPNS_26BattleObjectModuleAccessorERKN3phx8Vector3fE") LINKABLE;
|
||||
}
|
||||
|
||||
namespace StatusModule {
|
||||
u64 change_status_request_from_script(u64, int, bool) asm("_ZN3app8lua_bind52StatusModule__change_status_request_from_script_implEPNS_26BattleObjectModuleAccessorEib") LINKABLE;
|
||||
int status_kind(u64) asm("_ZN3app8lua_bind30StatusModule__status_kind_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
|
||||
int situation_kind(u64) asm("_ZN3app8lua_bind33StatusModule__situation_kind_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
|
||||
}
|
||||
|
||||
namespace WorkModule {
|
||||
// PT crashes if this doesn't return a bool?
|
||||
bool get_int(u64, int) asm("_ZN3app8lua_bind24WorkModule__get_int_implEPNS_26BattleObjectModuleAccessorEi") LINKABLE;
|
||||
int get_param_int(u64, u64, u64) asm("_ZN3app8lua_bind30WorkModule__get_param_int_implEPNS_26BattleObjectModuleAccessorEmm") LINKABLE;
|
||||
void inc_int(u64, int) asm("_ZN3app8lua_bind24WorkModule__inc_int_implEPNS_26BattleObjectModuleAccessorEi") LINKABLE;
|
||||
}
|
||||
namespace app::sv_system {
|
||||
u64 battle_object(u64) asm("_ZN3app9sv_system13battle_objectEP9lua_State") LINKABLE;
|
||||
u64 battle_object_module_accessor(u64) asm("_ZN3app9sv_system29battle_object_module_accessorEP9lua_State") LINKABLE;
|
||||
u8 battle_object_category(u64) asm("_ZN3app9sv_system22battle_object_categoryEP9lua_State") LINKABLE;
|
||||
int battle_object_kind(u64) asm("_ZN3app9sv_system18battle_object_kindEP9lua_State") LINKABLE;
|
||||
}
|
||||
|
||||
struct ACMD
|
||||
{
|
||||
L2CAgent* l2c_agent;
|
||||
u64 module_accessor;
|
||||
namespace app::lua_bind {
|
||||
namespace AttackModule {
|
||||
void clear_all(u64) asm("_ZN3app8lua_bind28AttackModule__clear_all_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
|
||||
}
|
||||
|
||||
ACMD(L2CAgent* agent) {
|
||||
l2c_agent = agent;
|
||||
module_accessor = app::sv_system::battle_object_module_accessor(l2c_agent->lua_state_agent);
|
||||
}
|
||||
namespace ControlModule {
|
||||
bool check_button_on(u64, int) asm("_ZN3app8lua_bind35ControlModule__check_button_on_implEPNS_26BattleObjectModuleAccessorEi") LINKABLE;
|
||||
}
|
||||
|
||||
void frame(float f) {
|
||||
app::sv_animcmd::frame(l2c_agent->lua_state_agent, f);
|
||||
l2c_agent->clear_lua_stack();
|
||||
}
|
||||
namespace EffectModule {
|
||||
// boma, effect, joint, pos, rot, size, random_pos, random_rot, NO_SCALE?, attr?, unkint1, unkint2
|
||||
uint req_on_joint(u64, u64, u64, const Vector3f*, const Vector3f*, float a6, const Vector3f*, const Vector3f*, bool, uint, int, int)
|
||||
asm("_ZN3app8lua_bind31EffectModule__req_on_joint_implEPNS_26BattleObjectModuleAccessorEN3phx6Hash40ES4_RKNS3_8Vector3fES7_fS7_S7_bjii") LINKABLE;
|
||||
|
||||
bool is_excute() {
|
||||
app::sv_animcmd::is_excute(l2c_agent->lua_state_agent);
|
||||
L2CValue is_excute;
|
||||
l2c_agent->get_lua_stack(1, &is_excute);
|
||||
bool excute = is_excute.raw;
|
||||
l2c_agent->clear_lua_stack();
|
||||
return excute;
|
||||
}
|
||||
void kill_kind(u64, u64, bool, bool) asm("_ZN3app8lua_bind28EffectModule__kill_kind_implEPNS_26BattleObjectModuleAccessorEN3phx6Hash40Ebb") LINKABLE;
|
||||
}
|
||||
|
||||
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);
|
||||
namespace FighterManager {
|
||||
u64 get_fighter_information(u64, int) asm("_ZN3app8lua_bind44FighterManager__get_fighter_information_implEPNS_14FighterManagerENS_14FighterEntryIDE") LINKABLE;
|
||||
}
|
||||
|
||||
acmd_func(l2c_agent->lua_state_agent);
|
||||
l2c_agent->clear_lua_stack();
|
||||
}
|
||||
namespace FighterInformation {
|
||||
bool is_operation_cpu(u64) asm("_ZN3app8lua_bind41FighterInformation__is_operation_cpu_implEPNS_18FighterInformationE") LINKABLE;
|
||||
}
|
||||
|
||||
void ATTACK(
|
||||
u64 i1,
|
||||
u64 i2,
|
||||
u64 h1,
|
||||
float f1,
|
||||
u64 i3,
|
||||
u64 i4,
|
||||
u64 i5,
|
||||
u64 i6,
|
||||
float f2,
|
||||
float f3,
|
||||
float f4,
|
||||
float f5,
|
||||
//void,
|
||||
//void,
|
||||
//void,
|
||||
float f6,
|
||||
float f7,
|
||||
u64 i7,
|
||||
u64 i8,
|
||||
u64 i9,
|
||||
u64 i10,
|
||||
float f8,
|
||||
u64 i11,
|
||||
u64 i12,
|
||||
u64 i13,
|
||||
u64 i14,
|
||||
u64 i15,
|
||||
u64 i16,
|
||||
u64 i17,
|
||||
u64 i18,
|
||||
u64 i19,
|
||||
u64 i20,
|
||||
u64 h2,
|
||||
u64 i21,
|
||||
u64 i22,
|
||||
u64 i23
|
||||
) {
|
||||
L2CValue hitbox_params[36] = {
|
||||
L2CValue(i1), // ID
|
||||
L2CValue(i2), // Unk
|
||||
L2CValue(h1), // Joint
|
||||
L2CValue(f1), // Damage
|
||||
L2CValue(i3), // Angle
|
||||
L2CValue(i4), // KBG
|
||||
L2CValue(i5), // WBKB
|
||||
L2CValue(i6), // BKB
|
||||
L2CValue(f2), // Size
|
||||
L2CValue(f3), // X
|
||||
L2CValue(f4), // Y
|
||||
L2CValue(f5), // Z
|
||||
L2CValue("void"), // X2
|
||||
L2CValue("void"), // Y2
|
||||
L2CValue("void"), // Z2
|
||||
L2CValue(f6), // Hitlag
|
||||
L2CValue(f7), // SDI
|
||||
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)
|
||||
};
|
||||
namespace MotionModule {
|
||||
float frame(u64) asm("_ZN3app8lua_bind24MotionModule__frame_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
|
||||
u64 motion_kind(u64) asm("_ZN3app8lua_bind30MotionModule__motion_kind_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 36; i++)
|
||||
l2c_agent->push_lua_stack(&hitbox_params[i]);
|
||||
namespace PostureModule {
|
||||
float lr(u64) asm("_ZN3app8lua_bind22PostureModule__lr_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
|
||||
float pos_x(u64) asm("_ZN3app8lua_bind25PostureModule__pos_x_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
|
||||
float pos_y(u64) asm("_ZN3app8lua_bind25PostureModule__pos_y_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
|
||||
float set_pos(u64, const Vector3f*) asm("_ZN3app8lua_bind27PostureModule__set_pos_implEPNS_26BattleObjectModuleAccessorERKN3phx8Vector3fE") LINKABLE;
|
||||
}
|
||||
|
||||
app::sv_animcmd::ATTACK(l2c_agent->lua_state_agent);
|
||||
namespace StatusModule {
|
||||
u64 change_status_request_from_script(u64, int, bool) asm("_ZN3app8lua_bind52StatusModule__change_status_request_from_script_implEPNS_26BattleObjectModuleAccessorEib") LINKABLE;
|
||||
int status_kind(u64) asm("_ZN3app8lua_bind30StatusModule__status_kind_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
|
||||
int situation_kind(u64) asm("_ZN3app8lua_bind33StatusModule__situation_kind_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
|
||||
}
|
||||
|
||||
l2c_agent->clear_lua_stack();
|
||||
}
|
||||
namespace WorkModule {
|
||||
float get_float(u64, int) asm("_ZN3app8lua_bind26WorkModule__get_float_implEPNS_26BattleObjectModuleAccessorEi") LINKABLE;
|
||||
bool get_int(u64, int) asm("_ZN3app8lua_bind24WorkModule__get_int_implEPNS_26BattleObjectModuleAccessorEi") LINKABLE; // this function must return a bool, otherwise Pokemon Trainer fails to load
|
||||
void inc_int(u64, int) asm("_ZN3app8lua_bind24WorkModule__inc_int_implEPNS_26BattleObjectModuleAccessorEi") LINKABLE;
|
||||
float get_param_float(u64, u64, u64) asm("_ZN3app8lua_bind32WorkModule__get_param_float_implEPNS_26BattleObjectModuleAccessorEmm") LINKABLE;
|
||||
int get_param_int(u64, u64, u64) asm("_ZN3app8lua_bind30WorkModule__get_param_int_implEPNS_26BattleObjectModuleAccessorEmm") LINKABLE;
|
||||
void on_flag(u64, int) asm("_ZN3app8lua_bind24WorkModule__on_flag_implEPNS_26BattleObjectModuleAccessorEi") LINKABLE;
|
||||
void off_flag(u64, int) asm("_ZN3app8lua_bind25WorkModule__off_flag_implEPNS_26BattleObjectModuleAccessorEi") LINKABLE;
|
||||
float set_float(u64, float, int) asm("_ZN3app8lua_bind26WorkModule__set_float_implEPNS_26BattleObjectModuleAccessorEfi") LINKABLE;
|
||||
int set_int(u64, int, int) asm("_ZN3app8lua_bind24WorkModule__set_int_implEPNS_26BattleObjectModuleAccessorEii") LINKABLE;
|
||||
}
|
||||
}
|
||||
|
||||
struct ACMD {
|
||||
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);
|
||||
}
|
||||
|
||||
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 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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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, // Rehit 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(), L2CValue(), L2CValue(), 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, // Rehit 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
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#ifndef CONST_VALUE_TABLE_H
|
||||
#define CONST_VALUE_TABLE_H
|
||||
|
||||
#define LUA_SCRIPT_LINE_MAX lua_const("LUA_SCRIPT_LINE_MAX")
|
||||
#define LUA_SCRIPT_LINE_SYSTEM lua_const("LUA_SCRIPT_LINE_SYSTEM")
|
||||
#define LUA_SCRIPT_LINE_SYSTEM_POST lua_const("LUA_SCRIPT_LINE_SYSTEM_POST")
|
||||
|
@ -15877,4 +15878,5 @@
|
|||
#define ITEM_ZOROARK_INSTANCE_WORK_INT_TARGET_STATE lua_const("ITEM_ZOROARK_INSTANCE_WORK_INT_TARGET_STATE")
|
||||
#define ITEM_ZOROARK_INSTANCE_WORK_FLOAT_THROWUP_LR lua_const("ITEM_ZOROARK_INSTANCE_WORK_FLOAT_THROWUP_LR")
|
||||
#define ITEM_ZOROARK_INSTANCE_WORK_FLAG_THROW_UP_GRAVITY_START lua_const("ITEM_ZOROARK_INSTANCE_WORK_FLAG_THROW_UP_GRAVITY_START")
|
||||
|
||||
#endif // CONST_VALUE_TABLE_H
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
|
||||
* code or tables extracted from it, as desired without restriction.
|
||||
*/
|
||||
|
||||
#ifndef CRC32_H
|
||||
#define CRC32_H
|
||||
|
||||
|
@ -55,8 +54,7 @@ const uint32_t crc32_tab[] = {
|
|||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||
};
|
||||
|
||||
uint32_t crc32_part(const void *buf, size_t size, uint32_t crc)
|
||||
{
|
||||
uint32_t crc32_part(const void *buf, size_t size, uint32_t crc) {
|
||||
const uint8_t* p = (const uint8_t*)buf;
|
||||
crc = crc ^ ~0U;
|
||||
while (size--)
|
||||
|
@ -64,8 +62,7 @@ uint32_t crc32_part(const void *buf, size_t size, uint32_t crc)
|
|||
return crc ^ ~0U;
|
||||
}
|
||||
|
||||
uint32_t crc32(const void *buf, size_t size)
|
||||
{
|
||||
uint32_t crc32(const void *buf, size_t size) {
|
||||
const uint8_t* p = (const uint8_t*)buf;
|
||||
uint32_t crc;
|
||||
crc = ~0U;
|
||||
|
@ -74,10 +71,9 @@ uint32_t crc32(const void *buf, size_t size)
|
|||
return crc ^ ~0U;
|
||||
}
|
||||
|
||||
uint64_t hash40(const char* data)
|
||||
{
|
||||
uint64_t hash40(const char* data) {
|
||||
size_t len = strlen(data);
|
||||
return crc32(data, len) | (len & 0xFF) << 32;
|
||||
return crc32(data, len) | (len & 0xFF) << 32;
|
||||
}
|
||||
|
||||
#endif // CRC32_H
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
#include "l2c.hpp"
|
||||
#include "saltysd_helper.hpp"
|
||||
#include <math.h>
|
||||
|
||||
#include "useful.h"
|
||||
#include "useful_visual.h"
|
||||
|
||||
#include "l2c_imports.hpp"
|
||||
#include "acmd_imports.hpp"
|
||||
#include "acmd_wrapper.hpp"
|
||||
#include "saltysd_helper.hpp"
|
||||
#include "const_value_table.h"
|
||||
#include "taunt_toggles.h"
|
||||
|
||||
using namespace lib;
|
||||
|
@ -10,138 +15,159 @@ using namespace app::sv_animcmd;
|
|||
|
||||
void (*AttackModule_set_attack_lua_state)(u64, u64);
|
||||
|
||||
Vector3f id_colors[8] = {
|
||||
{1.0f, 0.0f, 0.0f}, {0.7843f, 0.3529f, 1.0f},
|
||||
{1.0f, 0.7843f, 0.7843f}, {0.0f, 1.0f, 0.8431f},
|
||||
{1.0f, 0.4706f, 0.0f}, {0.7843f, 0.7059f, 0.0f},
|
||||
{0.7843f, 0.0f, 1.0f}, {0.3765f, 0.2863f, 0.5294f},
|
||||
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
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void generate_hitbox_effects(L2CAgent *l2c_agent, L2CValue *id, L2CValue *bone,
|
||||
L2CValue *size, L2CValue *x, L2CValue *y,
|
||||
L2CValue *z, L2CValue *x2, L2CValue *y2,
|
||||
L2CValue *z2) {
|
||||
Vector3f color = id_colors[id->raw % 8];
|
||||
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 sizeMult = 19.0 / 200.0;
|
||||
Hash40 shieldEffectHash = {.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(shieldEffectHash.hash);
|
||||
L2CValue xRot(0.0f);
|
||||
L2CValue yRot(0.0f);
|
||||
L2CValue zRot(0.0f);
|
||||
L2CValue terminate(true);
|
||||
L2CValue effectSize((float)size->raw_float * sizeMult);
|
||||
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;
|
||||
}
|
||||
|
||||
// Extended Hitboxes if x2, y2, z2 are not L2CValue::nil
|
||||
int num_effects;
|
||||
if (x2->type != L2C_void && y2->type != L2C_void && z2->type != L2C_void) {
|
||||
num_effects = 4;
|
||||
} else {
|
||||
*x2 = *x;
|
||||
*y2 = *y;
|
||||
*z2 = *z;
|
||||
num_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 < num_effects; i++) {
|
||||
L2CValue currX(x->raw_float + ((x2->raw_float - x->raw_float) / 3 * i));
|
||||
L2CValue currY(y->raw_float + ((y2->raw_float - y->raw_float) / 3 * i));
|
||||
L2CValue currZ(z->raw_float + ((z2->raw_float - z->raw_float) / 3 * i));
|
||||
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 });
|
||||
|
||||
ACMD acmd(l2c_agent);
|
||||
acmd.wrap(EFFECT_FOLLOW_NO_SCALE,
|
||||
{shieldEffect, *bone, currX, currY, currZ, xRot, yRot, zRot, effectSize, terminate}
|
||||
);
|
||||
// set to hitbox ID color
|
||||
acmd.wrap(LAST_EFFECT_SET_COLOR, { red, green, blue });
|
||||
|
||||
// Set to hitbox ID color
|
||||
acmd.wrap(LAST_EFFECT_SET_COLOR, {red, green, blue});
|
||||
|
||||
// Speed up animation by rate to remove pulsing effect
|
||||
// LAST_EFFECT_SET_RATE(Rate)
|
||||
acmd.wrap(LAST_EFFECT_SET_RATE, {rate});
|
||||
}
|
||||
// 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, wkb, bkb, size, x, y, z, x2, y2, z2;
|
||||
l2c_agent.get_lua_stack(1, &id);
|
||||
l2c_agent.get_lua_stack(3, &bone);
|
||||
l2c_agent.get_lua_stack(4, &damage);
|
||||
l2c_agent.get_lua_stack(5, &angle);
|
||||
l2c_agent.get_lua_stack(6, &kbg);
|
||||
l2c_agent.get_lua_stack(7, &wkb);
|
||||
l2c_agent.get_lua_stack(8, &bkb);
|
||||
l2c_agent.get_lua_stack(9, &size);
|
||||
l2c_agent.get_lua_stack(10, &x);
|
||||
l2c_agent.get_lua_stack(11, &y);
|
||||
l2c_agent.get_lua_stack(12, &z);
|
||||
l2c_agent.get_lua_stack(13, &x2);
|
||||
l2c_agent.get_lua_stack(14, &y2);
|
||||
l2c_agent.get_lua_stack(15, &z2);
|
||||
// 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
|
||||
|
||||
// original code: parse lua stack and call AttackModule::set_attack()
|
||||
AttackModule_set_attack_lua_state(LOAD64(LOAD64(a1 - 8) + 416LL), a1);
|
||||
// original code: parse lua stack and call AttackModule::set_attack()
|
||||
AttackModule_set_attack_lua_state(LOAD64(LOAD64(a1 - 8) + 416LL), a1);
|
||||
|
||||
if (HITBOX_VIS && is_training_mode()) {
|
||||
// Generate hitbox effect(s)
|
||||
generate_hitbox_effects(&l2c_agent, &id, &bone, &size, &x, &y, &z, &x2, &y2, &z2);
|
||||
}
|
||||
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.6f + 0.4f * 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);
|
||||
}
|
||||
|
||||
u64 v1, v2, i;
|
||||
v1 = a1;
|
||||
u64 v1, v2, i;
|
||||
v1 = a1;
|
||||
|
||||
// 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;
|
||||
}
|
||||
// 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 hitbox_vis_main() {
|
||||
AttackModule_set_attack_lua_state =
|
||||
(void (*)(u64, u64))SaltySDCore_FindSymbol("_ZN3app10sv_animcmd6ATTACKEP9lua_State") + 0xD0 - 0x70;
|
||||
|
||||
SaltySD_function_replace_sym(
|
||||
"_ZN3app10sv_animcmd6ATTACKEP9lua_State",
|
||||
(u64)&ATTACK_replace);
|
||||
|
||||
SaltySD_function_replace_sym(
|
||||
"_ZN3app8lua_bind28AttackModule__clear_all_implEPNS_26BattleObjectModuleAccessorE",
|
||||
(u64)&AttackModule::clear_all_replace);
|
||||
}
|
||||
AttackModule_set_attack_lua_state = (void (*)(u64, u64))SaltySDCore_FindSymbol("_ZN3app10sv_animcmd6ATTACKEP9lua_State") + 0xD0 - 0x70;
|
||||
SaltySD_function_replace_sym(
|
||||
"_ZN3app10sv_animcmd6ATTACKEP9lua_State",
|
||||
(u64)&ATTACK_replace);
|
||||
SaltySD_function_replace_sym(
|
||||
"_ZN3app8lua_bind28AttackModule__clear_all_implEPNS_26BattleObjectModuleAccessorE",
|
||||
(u64)&AttackModule::clear_all_replace);
|
||||
}
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
#ifndef L2C_H
|
||||
#define L2C_H
|
||||
|
||||
typedef struct Hash40
|
||||
{
|
||||
uint64_t hash : 40;
|
||||
} Hash40;
|
||||
|
||||
typedef struct Vector3f
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
} Vector3f;
|
||||
|
||||
#endif // L2C_H
|
|
@ -1,138 +1,151 @@
|
|||
#ifndef L2C_IMPORTS_H
|
||||
#define L2C_IMPORTS_H
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
#include "l2c.hpp"
|
||||
#include "lua_bind_hash.hpp"
|
||||
#include <math.h>
|
||||
|
||||
#define LOAD64 *(u64 *)
|
||||
#include "useful.h"
|
||||
|
||||
#include "lua_bind_hash.hpp"
|
||||
|
||||
u64 is_training_mode(void) asm("_ZN3app9smashball16is_training_modeEv") LINKABLE;
|
||||
|
||||
namespace lib
|
||||
{
|
||||
enum L2CVarType
|
||||
{
|
||||
L2C_void = 0,
|
||||
L2C_bool = 1,
|
||||
L2C_integer = 2,
|
||||
L2C_number = 3,
|
||||
L2C_pointer = 4,
|
||||
L2C_table = 5,
|
||||
L2C_inner_function = 6,
|
||||
L2C_hash = 7,
|
||||
L2C_string = 8,
|
||||
};
|
||||
namespace lib {
|
||||
enum L2CVarType {
|
||||
L2C_void = 0,
|
||||
L2C_bool = 1,
|
||||
L2C_integer = 2,
|
||||
L2C_number = 3,
|
||||
L2C_pointer = 4,
|
||||
L2C_table = 5,
|
||||
L2C_inner_function = 6,
|
||||
L2C_hash = 7,
|
||||
L2C_string = 8,
|
||||
};
|
||||
|
||||
struct L2CTable_meta
|
||||
{
|
||||
uint64_t a;
|
||||
uint64_t b;
|
||||
uint64_t c;
|
||||
uint64_t d;
|
||||
};
|
||||
typedef struct L2CTable_meta {
|
||||
uint64_t a;
|
||||
uint64_t b;
|
||||
uint64_t c;
|
||||
uint64_t d;
|
||||
} L2CTable_meta;
|
||||
|
||||
struct L2CTable
|
||||
{
|
||||
uint32_t refcnt;
|
||||
uint32_t unk;
|
||||
|
||||
uint64_t begin; // L2CValue*
|
||||
uint64_t end; // L2CValue*
|
||||
uint64_t also_end; // L2CValue*
|
||||
struct L2CTable_meta meta;
|
||||
uint64_t unk_ptr;
|
||||
};
|
||||
typedef struct L2CTable {
|
||||
uint32_t refcnt;
|
||||
uint32_t unk;
|
||||
|
||||
struct L2CInnerFunctionBase
|
||||
{
|
||||
uint64_t unk;
|
||||
uint32_t refcnt;
|
||||
} L2CInnerFunctionBase;
|
||||
uint64_t begin; // L2CValue*
|
||||
uint64_t end; // L2CValue*
|
||||
uint64_t also_end; // L2CValue*
|
||||
struct L2CTable_meta meta;
|
||||
uint64_t unk_ptr;
|
||||
} L2CTable;
|
||||
|
||||
struct L2CValue
|
||||
{
|
||||
uint32_t type;
|
||||
uint32_t unk;
|
||||
union
|
||||
{
|
||||
uint64_t raw;
|
||||
float raw_float;
|
||||
void* raw_pointer;
|
||||
struct L2CTable* raw_table;
|
||||
struct L2CInnerFunctionBase* raw_innerfunc;
|
||||
//std::string* raw_string;
|
||||
};
|
||||
typedef struct L2CInnerFunctionBase {
|
||||
uint64_t unk;
|
||||
uint32_t refcnt;
|
||||
} L2CInnerFunctionBase;
|
||||
|
||||
L2CValue() {}
|
||||
struct L2CValue {
|
||||
uint32_t type;
|
||||
uint32_t unk;
|
||||
union {
|
||||
uint64_t raw;
|
||||
float raw_float;
|
||||
// void* raw_pointer;
|
||||
// struct L2CTable* raw_table;
|
||||
// struct L2CInnerFunctionBase* raw_innerfunc;
|
||||
//std::string* raw_string;
|
||||
};
|
||||
|
||||
L2CValue(bool val) {
|
||||
type = L2C_bool;
|
||||
raw = val;
|
||||
}
|
||||
L2CValue() {
|
||||
type = L2C_void;
|
||||
}
|
||||
|
||||
L2CValue(u64 val) {
|
||||
type = L2C_integer;
|
||||
raw = val;
|
||||
}
|
||||
L2CValue(bool val) {
|
||||
type = L2C_bool;
|
||||
raw = val;
|
||||
}
|
||||
|
||||
L2CValue(float val) {
|
||||
type = L2C_number;
|
||||
raw_float = val;
|
||||
}
|
||||
L2CValue(int val) {
|
||||
type = L2C_integer;
|
||||
raw = val;
|
||||
}
|
||||
|
||||
L2CValue(const char* str) {
|
||||
type = L2C_void;
|
||||
}
|
||||
L2CValue(u64 val) {
|
||||
type = L2C_integer;
|
||||
raw = val;
|
||||
}
|
||||
|
||||
};
|
||||
L2CValue(float val) {
|
||||
if (isnan(val)) {
|
||||
type = L2C_void;
|
||||
} else {
|
||||
type = L2C_number;
|
||||
raw_float = val;
|
||||
}
|
||||
}
|
||||
|
||||
struct L2CAgent
|
||||
{
|
||||
uint64_t vtable;
|
||||
uint64_t lua_state_agent;
|
||||
uint64_t unk10;
|
||||
uint64_t unk18;
|
||||
uint64_t unk20;
|
||||
uint64_t unk28;
|
||||
uint64_t unk30;
|
||||
uint64_t unk38;
|
||||
uint64_t lua_state_agentbase;
|
||||
L2CValue(double val) {
|
||||
if (isnan(val)) {
|
||||
type = L2C_void;
|
||||
} else {
|
||||
type = L2C_number;
|
||||
raw_float = val;
|
||||
}
|
||||
}
|
||||
|
||||
L2CAgent* L2CAgent_constr(u64 lua_state) asm("_ZN3lib8L2CAgentC2EP9lua_State") LINKABLE;
|
||||
u64 push_lua_stack(L2CValue* l2c_value) asm("_ZN3lib8L2CAgent14push_lua_stackERKNS_8L2CValueE") LINKABLE;
|
||||
// pop_lua_stack
|
||||
// Notes:
|
||||
// Actually takes three arguments, but the third is given through X8 due to how
|
||||
// AArch64 treats struct pointers that are used as pass by reference to get the value.
|
||||
// Thus, my current solution is to use inline ASM before using this to pass the
|
||||
// last arg. This is done using asm("mov x8, %x0" : : "r"(&popped) : "x8" );, where
|
||||
// popped is an L2CValue that will be populated by the function.
|
||||
// FURTHERMORE, this function does NOT actually pop the stack, it only returns the value at the
|
||||
// position indicated by the second argument.
|
||||
// This index is either positive, meaning absolute position in the stack, or negative,
|
||||
// which is more traditional, i.e. -1 is the top of the stack.
|
||||
//__int64_t (*lib_L2CAgent_pop_lua_stack)(__int64_t, int);
|
||||
u64 pop_lua_stack(int index) asm("_ZN3lib8L2CAgent13pop_lua_stackEi") LINKABLE;
|
||||
operator bool() asm("_ZNK3lib8L2CValuecvbEv") LINKABLE;
|
||||
|
||||
void get_lua_stack(int index, lib::L2CValue* l2c_val) {
|
||||
asm("mov x8, %x0" : : "r"(l2c_val) : "x8" );
|
||||
pop_lua_stack(index);
|
||||
}
|
||||
void push_variadic(u64, const char*, void*) asm("_ZN3lib8L2CValue13push_variadicEmPKcRNS_7utility8VariadicE") LINKABLE;
|
||||
};
|
||||
|
||||
u64 sv_set_function_hash(u64 (*func)(L2CAgent*, void*), u64 hash) asm("_ZN3lib8L2CAgent20sv_set_function_hashEPvN3phx6Hash40E") LINKABLE;
|
||||
u64 clear_lua_stack() asm("_ZN3lib8L2CAgent15clear_lua_stackEv") LINKABLE;
|
||||
};
|
||||
struct L2CAgent {
|
||||
uint64_t vtable;
|
||||
uint64_t lua_state_agent;
|
||||
uint64_t unk10;
|
||||
uint64_t unk18;
|
||||
uint64_t unk20;
|
||||
uint64_t unk28;
|
||||
uint64_t unk30;
|
||||
uint64_t unk38;
|
||||
uint64_t lua_state_agentbase;
|
||||
|
||||
bool lua_bind_get_value(u64, int*) asm("_ZN3lib18lua_bind_get_valueIiEEbmRT_") LINKABLE;
|
||||
L2CAgent* L2CAgent_constr(u64 lua_state) asm("_ZN3lib8L2CAgentC2EP9lua_State") LINKABLE;
|
||||
u64 push_lua_stack(L2CValue* l2c_value) asm("_ZN3lib8L2CAgent14push_lua_stackERKNS_8L2CValueE") LINKABLE;
|
||||
// pop_lua_stack
|
||||
// Notes:
|
||||
// Actually takes three arguments, but the third is given through X8 due to how
|
||||
// AArch64 treats struct pointers that are used as pass by reference to get the value.
|
||||
// Thus, my current solution is to use inline ASM before using this to pass the
|
||||
// last arg. This is done using asm("mov x8, %x0" : : "r"(&popped) : "x8" );, where
|
||||
// popped is an L2CValue that will be populated by the function.
|
||||
// FURTHERMORE, this function does NOT actually pop the stack, it only returns the value at the
|
||||
// position indicated by the second argument.
|
||||
// This index is either positive, meaning absolute position in the stack, or negative,
|
||||
// which is more traditional, i.e. -1 is the top of the stack.
|
||||
//__int64_t (*lib_L2CAgent_pop_lua_stack)(__int64_t, int);
|
||||
u64 pop_lua_stack(int index) asm("_ZN3lib8L2CAgent13pop_lua_stackEi") LINKABLE;
|
||||
|
||||
int lua_const(const char* str) {
|
||||
int val;
|
||||
if (lua_bind_get_value(lua_bind_hash_str(str), &val))
|
||||
return val;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
void get_lua_stack(int index, lib::L2CValue* l2c_val) {
|
||||
asm("mov x8, %x0" : : "r"(l2c_val) : "x8" );
|
||||
pop_lua_stack(index);
|
||||
}
|
||||
|
||||
u64 sv_set_function_hash(u64 (*func)(L2CAgent*, void*), u64 hash) asm("_ZN3lib8L2CAgent20sv_set_function_hashEPvN3phx6Hash40E") LINKABLE;
|
||||
u64 clear_lua_stack() asm("_ZN3lib8L2CAgent15clear_lua_stackEv") LINKABLE;
|
||||
};
|
||||
|
||||
bool lua_bind_get_value(u64, int*) asm("_ZN3lib18lua_bind_get_valueIiEEbmRT_") LINKABLE;
|
||||
|
||||
int lua_const(const char* str) {
|
||||
int val;
|
||||
if (lua_bind_get_value(lua_bind_hash_str(str), &val))
|
||||
return val;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // L2C_IMPORTS_H
|
||||
|
|
|
@ -1,97 +1,101 @@
|
|||
#ifndef LUA_BIND_HASH_H
|
||||
#define LUA_BIND_HASH_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
uint64_t lua_bind_hash(const void* data_, size_t len) {
|
||||
int64_t *data = (int64_t*)data_;
|
||||
size_t hash = len;
|
||||
int64_t hash_add = 0x27d4eb2f165667c4;
|
||||
int64_t* data_end = (int64_t *)((int64_t)data + len);
|
||||
int64_t *data = (int64_t*)data_;
|
||||
size_t hash = len;
|
||||
int64_t hash_add = 0x27d4eb2f165667c4;
|
||||
int64_t* data_end = (int64_t *)((int64_t)data + len);
|
||||
|
||||
uint64_t hash_vals[4] = {
|
||||
0x60ea27eeadc0b5d5,
|
||||
0xc2b2ae3d27d4eb4e,
|
||||
0xffffffffffffffff,
|
||||
0x61c8864e7a143578,
|
||||
};
|
||||
uint64_t hash_vals[4] = {
|
||||
0x60ea27eeadc0b5d5,
|
||||
0xc2b2ae3d27d4eb4e,
|
||||
0xffffffffffffffff,
|
||||
0x61c8864e7a143578,
|
||||
};
|
||||
|
||||
uint64_t hash_vals_mid[4];
|
||||
uint64_t hash_vals_mid[4];
|
||||
|
||||
const uint64_t hash_vals_end[4] = {
|
||||
0x3c6ef3630bd7950e,
|
||||
0x1bbcd8c2f5e54380,
|
||||
0x779b185ebca87000,
|
||||
0xe6c617af2a1c0000
|
||||
};
|
||||
const uint64_t hash_vals_end[4] = {
|
||||
0x3c6ef3630bd7950e,
|
||||
0x1bbcd8c2f5e54380,
|
||||
0x779b185ebca87000,
|
||||
0xe6c617af2a1c0000
|
||||
};
|
||||
|
||||
const uint64_t hash_vals_end_2[4] = {
|
||||
0x3f,
|
||||
0x39,
|
||||
0x34,
|
||||
0x2e
|
||||
};
|
||||
const uint64_t hash_vals_end_2[4] = {
|
||||
0x3f,
|
||||
0x39,
|
||||
0x34,
|
||||
0x2e
|
||||
};
|
||||
|
||||
const uint64_t MULT1 = 0x87bcb65480000000; // -0x784349ab80000000
|
||||
const uint64_t MULT2 = 0xdef35b010f796ca9; // -0x210ca4fef0869357
|
||||
const uint64_t MULT3 = 0x9e3779b185ebca87; // -0x61c8864e7a143579
|
||||
const uint64_t MULT4 = 0xc2b2ae3d27d4eb4f; // -0x3d4d51c2d82b14b1
|
||||
const uint64_t MULT5 = 0x93ea75a780000000; // -0x6c158a5880000000
|
||||
const uint64_t MULT6 = 0x27d4eb2f165667c5;
|
||||
const uint64_t ADD1 = 0x85ebca77c2b2ae63;
|
||||
const uint64_t ADD2 = 0x165667b19e3779f9;
|
||||
|
||||
if (len >= 32) {
|
||||
do {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
hash_vals[i] += data[i] * MULT4;
|
||||
hash_vals_mid[i] = hash_vals[i] >> 0x21 | hash_vals[i] * 0x80000000;
|
||||
hash_vals[i] = hash_vals_mid[i] * MULT3;
|
||||
}
|
||||
|
||||
data = data + 4;
|
||||
} while (data <= data_end + -4);
|
||||
uint64_t val = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
val += (hash_vals_mid[i] * hash_vals_end[i] | hash_vals[i] >> hash_vals_end_2[i]);
|
||||
}
|
||||
const uint64_t MULT1 = 0x87bcb65480000000; // -0x784349ab80000000
|
||||
const uint64_t MULT2 = 0xdef35b010f796ca9; // -0x210ca4fef0869357
|
||||
const uint64_t MULT3 = 0x9e3779b185ebca87; // -0x61c8864e7a143579
|
||||
const uint64_t MULT4 = 0xc2b2ae3d27d4eb4f; // -0x3d4d51c2d82b14b1
|
||||
const uint64_t MULT5 = 0x93ea75a780000000; // -0x6c158a5880000000
|
||||
const uint64_t MULT6 = 0x27d4eb2f165667c5;
|
||||
const uint64_t ADD1 = 0x85ebca77c2b2ae63;
|
||||
const uint64_t ADD2 = 0x165667b19e3779f9;
|
||||
|
||||
if (len >= 32) {
|
||||
do {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
hash_vals[i] += data[i] * MULT4;
|
||||
hash_vals_mid[i] = hash_vals[i] >> 0x21 | hash_vals[i] * 0x80000000;
|
||||
hash_vals[i] = hash_vals_mid[i] * MULT3;
|
||||
}
|
||||
|
||||
data = data + 4;
|
||||
} while (data <= data_end + -4);
|
||||
uint64_t val = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
val += (hash_vals_mid[i] * hash_vals_end[i] | hash_vals[i] >> hash_vals_end_2[i]);
|
||||
}
|
||||
|
||||
val = (val ^ (hash_vals_mid[0] * MULT1 | hash_vals_mid[0] * MULT2 >> 0x21) * MULT3) * MULT3;
|
||||
for (int i = 1; i < 4; i++) {
|
||||
val = (val + ADD1 ^ (hash_vals_mid[i] * MULT1 | hash_vals_mid[i] * MULT2 >> 0x21) * MULT3) * MULT3;
|
||||
}
|
||||
val += ADD1;
|
||||
val = (val ^ (hash_vals_mid[0] * MULT1 | hash_vals_mid[0] * MULT2 >> 0x21) * MULT3) * MULT3;
|
||||
for (int i = 1; i < 4; i++) {
|
||||
val = (val + ADD1 ^ (hash_vals_mid[i] * MULT1 | hash_vals_mid[i] * MULT2 >> 0x21) * MULT3) * MULT3;
|
||||
}
|
||||
val += ADD1;
|
||||
|
||||
hash_add = val;
|
||||
}
|
||||
hash_add = val;
|
||||
}
|
||||
|
||||
hash += hash_add;
|
||||
for (; data + 1 <= data_end; data++) {
|
||||
hash = (*data * MULT5 | (*data * MULT4) >> 0x21) *
|
||||
MULT3 ^ hash;
|
||||
hash = (hash >> 0x25 | hash << 0x1b) * MULT3 + ADD1;
|
||||
}
|
||||
hash += hash_add;
|
||||
for (; data + 1 <= data_end; data++) {
|
||||
hash = (*data * MULT5 | (*data * MULT4) >> 0x21) * MULT3 ^ hash;
|
||||
hash = (hash >> 0x25 | hash << 0x1b) * MULT3 + ADD1;
|
||||
}
|
||||
|
||||
int32_t* data_32 = (int32_t*) data;
|
||||
if ((int64_t *)(data_32 + 1) <= data_end) {
|
||||
hash = (uint64_t)*data_32 * MULT3 ^ hash;
|
||||
hash = (hash >> 0x29 | hash << 0x17) * MULT4 + ADD2;
|
||||
data = (int64_t *)(data_32 + 1);
|
||||
}
|
||||
int32_t* data_32 = (int32_t*) data;
|
||||
if ((int64_t *)(data_32 + 1) <= data_end) {
|
||||
hash = (uint64_t)*data_32 * MULT3 ^ hash;
|
||||
hash = (hash >> 0x29 | hash << 0x17) * MULT4 + ADD2;
|
||||
data = (int64_t *)(data_32 + 1);
|
||||
}
|
||||
|
||||
int8_t* data_8 = (int8_t*) data;
|
||||
int8_t* data_8 = (int8_t*) data;
|
||||
|
||||
for (; data != data_end; data = (int64_t*)data_8) {
|
||||
hash = (uint64_t)(*data_8) * MULT6 ^ hash;
|
||||
hash = (hash >> 0x35 | hash << 0xb) * MULT3;
|
||||
data_8++;
|
||||
}
|
||||
|
||||
uint64_t final_hash = (hash ^ hash >> 0x21) * MULT4;
|
||||
final_hash = (final_hash ^ final_hash >> 0x1d) * ADD2;
|
||||
return final_hash ^ final_hash >> 0x20;
|
||||
for (; data != data_end; data = (int64_t*)data_8) {
|
||||
hash = (uint64_t)(*data_8) * MULT6 ^ hash;
|
||||
hash = (hash >> 0x35 | hash << 0xb) * MULT3;
|
||||
data_8++;
|
||||
}
|
||||
|
||||
uint64_t final_hash = (hash ^ hash >> 0x21) * MULT4;
|
||||
final_hash = (final_hash ^ final_hash >> 0x1d) * ADD2;
|
||||
return final_hash ^ final_hash >> 0x20;
|
||||
}
|
||||
|
||||
uint64_t lua_bind_hash_str(const char* str) {
|
||||
return lua_bind_hash(str, strlen(str));
|
||||
}
|
||||
return lua_bind_hash(str, strlen(str));
|
||||
}
|
||||
|
||||
#endif // LUA_BIND_HASH_H
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
#ifndef LUA_HELPER_H
|
||||
#define LUA_HELPER_H
|
||||
#include <switch.h>
|
||||
#include "l2c_imports.hpp"
|
||||
|
||||
|
||||
|
||||
#endif // LUA_HELPER_H
|
108
source/main.cpp
108
source/main.cpp
|
@ -1,7 +1,6 @@
|
|||
#include <switch.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/iosupport.h>
|
||||
|
@ -15,21 +14,23 @@
|
|||
#include "saltysd_dynamic.h"
|
||||
|
||||
#include "saltysd_helper.hpp"
|
||||
#include "l2c_imports.hpp"
|
||||
#include "acmd_imports.hpp"
|
||||
|
||||
#include "script_replacement.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;
|
||||
|
@ -38,61 +39,58 @@ Handle orig_main_thread;
|
|||
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;
|
||||
void __libnx_init(void* ctx, Handle main_thread, void* saved_lr) {
|
||||
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();
|
||||
void __attribute__((weak)) NORETURN __libnx_exit(int rc) {
|
||||
// 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");
|
||||
|
||||
// Get anchor for imports
|
||||
// do not remove if you plan on using IMPORT
|
||||
ANCHOR_ABS = SaltySDCore_getCodeStart();
|
||||
|
||||
/*
|
||||
Example of string replacement:
|
||||
replaces the title screen's version number with the string
|
||||
below.
|
||||
*/
|
||||
/*
|
||||
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);
|
||||
}
|
||||
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);
|
||||
|
||||
hitbox_vis_main();
|
||||
training_mods_main();
|
||||
// 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);
|
||||
__libnx_exit(0);
|
||||
}
|
||||
|
||||
|
|
126
source/nn_ro.h
126
source/nn_ro.h
|
@ -1,78 +1,82 @@
|
|||
#ifndef NN_RO_H
|
||||
#define NN_RO_H
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
#define nn_ro_LoadModule _ZN2nn2ro10LoadModuleEPNS0_6ModuleEPKvPvmi
|
||||
extern uint64_t _ZN2nn2ro10LoadModuleEPNS0_6ModuleEPKvPvmi(void* module, void const* unk_1, void* unk_2, unsigned long unk_3, int unk_4) LINKABLE;
|
||||
|
||||
typedef unsigned char undefined;
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned char dwfenc;
|
||||
typedef unsigned int dword;
|
||||
typedef long long longlong;
|
||||
typedef unsigned long long qword;
|
||||
typedef unsigned char uchar;
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned long ulong;
|
||||
typedef unsigned long long ulonglong;
|
||||
typedef unsigned char undefined1;
|
||||
typedef unsigned short undefined2;
|
||||
typedef unsigned int undefined3;
|
||||
typedef unsigned int undefined4;
|
||||
typedef unsigned long long undefined5;
|
||||
typedef unsigned long long undefined6;
|
||||
typedef unsigned long long undefined7;
|
||||
typedef unsigned long long undefined8;
|
||||
typedef unsigned short ushort;
|
||||
typedef unsigned short word;
|
||||
typedef unsigned char undefined;
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned char dwfenc;
|
||||
typedef unsigned int dword;
|
||||
typedef long long longlong;
|
||||
typedef unsigned long long qword;
|
||||
typedef unsigned char uchar;
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned long ulong;
|
||||
typedef unsigned long long ulonglong;
|
||||
typedef unsigned char undefined1;
|
||||
typedef unsigned short undefined2;
|
||||
typedef unsigned int undefined3;
|
||||
typedef unsigned int undefined4;
|
||||
typedef unsigned long long undefined5;
|
||||
typedef unsigned long long undefined6;
|
||||
typedef unsigned long long undefined7;
|
||||
typedef unsigned long long undefined8;
|
||||
typedef unsigned short ushort;
|
||||
typedef unsigned short word;
|
||||
|
||||
enum module_state {module_unloaded, module_loaded};
|
||||
|
||||
typedef struct RoModule_t {
|
||||
struct RoModule_t *next;
|
||||
struct RoModule_t *prev;
|
||||
union {
|
||||
void *rel;
|
||||
void *rela;
|
||||
void *raw;
|
||||
} rela_or_rel_plt;
|
||||
union {
|
||||
void *rel;
|
||||
void *rela;
|
||||
} rela_or_rel;
|
||||
uint64_t module_base;
|
||||
void *dyanmic;
|
||||
bool is_rela;
|
||||
uint64_t rela_or_rel_plt_size;
|
||||
void (*dt_init)(void);
|
||||
void (*dt_fini)(void);
|
||||
uint32_t *hash_bucket;
|
||||
uint32_t *hash_chain;
|
||||
char *dynstr;
|
||||
void *dynsym;
|
||||
uint64_t dynstr_size;
|
||||
void **got;
|
||||
uint64_t rela_dyn_size;
|
||||
uint64_t rel_dyn_size;
|
||||
uint64_t rel_count;
|
||||
uint64_t rela_count;
|
||||
uint64_t hash_nchain_value;
|
||||
uint64_t hash_nbucket_value;
|
||||
uint64_t got_stub_ptr;
|
||||
struct RoModule_t *next;
|
||||
struct RoModule_t *prev;
|
||||
union {
|
||||
void *rel;
|
||||
void *rela;
|
||||
void *raw;
|
||||
} rela_or_rel_plt;
|
||||
union {
|
||||
void *rel;
|
||||
void *rela;
|
||||
} rela_or_rel;
|
||||
uint64_t module_base;
|
||||
void *dyanmic;
|
||||
bool is_rela;
|
||||
uint64_t rela_or_rel_plt_size;
|
||||
void (*dt_init)(void);
|
||||
void (*dt_fini)(void);
|
||||
uint32_t *hash_bucket;
|
||||
uint32_t *hash_chain;
|
||||
char *dynstr;
|
||||
void *dynsym;
|
||||
uint64_t dynstr_size;
|
||||
void **got;
|
||||
uint64_t rela_dyn_size;
|
||||
uint64_t rel_dyn_size;
|
||||
uint64_t rel_count;
|
||||
uint64_t rela_count;
|
||||
uint64_t hash_nchain_value;
|
||||
uint64_t hash_nbucket_value;
|
||||
uint64_t got_stub_ptr;
|
||||
} RoModule;
|
||||
|
||||
typedef struct Module_t {
|
||||
RoModule *module;
|
||||
enum module_state state;
|
||||
uintptr_t module_address;
|
||||
uintptr_t bss_address;
|
||||
RoModule *module;
|
||||
enum module_state state;
|
||||
uintptr_t module_address;
|
||||
uintptr_t bss_address;
|
||||
} Module;
|
||||
|
||||
typedef struct SmashModule { /* PlaceHolder Structure */
|
||||
Module module;
|
||||
void * field_0x20;
|
||||
void * src_buffer;
|
||||
char name[256]; /* Created by retype action */
|
||||
undefined field_0x130;
|
||||
undefined field_0x131;
|
||||
undefined4 is_loaded; // bool
|
||||
Module module;
|
||||
void *field_0x20;
|
||||
void *src_buffer;
|
||||
char name[256]; /* Created by retype action */
|
||||
undefined field_0x130;
|
||||
undefined field_0x131;
|
||||
undefined4 is_loaded; // bool
|
||||
} SmashModule;
|
||||
|
||||
# endif // NN_RO_H
|
||||
|
|
|
@ -23,21 +23,21 @@ using namespace app::lua_bind;
|
|||
*/
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -107,12 +107,12 @@ const char segment_rev[15] = {
|
|||
};
|
||||
|
||||
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};
|
||||
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,
|
||||
|
@ -150,9 +150,9 @@ void print_char( u64 module_accessor, char to_print, int line_num, float horiz_o
|
|||
const float* segment;
|
||||
int index = segment_str[i] - 'a';
|
||||
|
||||
if (facing_left == -1)
|
||||
if (facing_left == -1) {
|
||||
index = segment_rev[index] - 'a';
|
||||
|
||||
}
|
||||
segment = segment_dict[index];
|
||||
|
||||
float z = segment[0];
|
||||
|
@ -170,7 +170,7 @@ void print_char( u64 module_accessor, char to_print, int line_num, float horiz_o
|
|||
|
||||
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;
|
||||
|
@ -179,8 +179,9 @@ void print_string( u64 module_accessor, const char* print_str) {
|
|||
|
||||
float facing_left = PostureModule::lr(module_accessor);
|
||||
|
||||
if (strlen(print_str) <= 8 && strchr(print_str, '\n') == NULL)
|
||||
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++) {
|
||||
|
@ -196,10 +197,11 @@ void print_string( u64 module_accessor, const char* print_str) {
|
|||
|
||||
char_num++;
|
||||
// short characters
|
||||
if (curr_char == 'D' || curr_char == '1' )
|
||||
if (curr_char == 'D' || curr_char == '1') {
|
||||
horiz_offset += facing_left * (RAYGUN_LENGTH/2 + 3);
|
||||
else
|
||||
horiz_offset += facing_left * (RAYGUN_LENGTH+3);
|
||||
} else {
|
||||
horiz_offset += facing_left * (RAYGUN_LENGTH + 3);
|
||||
}
|
||||
|
||||
if (char_num > 8) {
|
||||
horiz_offset = 0;
|
||||
|
@ -209,4 +211,4 @@ void print_string( u64 module_accessor, const char* print_str) {
|
|||
}
|
||||
}
|
||||
|
||||
#endif // RAYGUN_PRINTER_H
|
||||
#endif // RAYGUN_PRINTER_H
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
#include "useful.h"
|
||||
|
||||
extern "C" {
|
||||
u64 SaltySDCore_getCodeStart() LINKABLE;
|
||||
u64 SaltySDCore_getCodeSize() LINKABLE;
|
||||
u64 SaltySDCore_findCode(u8* code, size_t size) LINKABLE;
|
||||
u64 SaltySDCore_getCodeStart() LINKABLE;
|
||||
u64 SaltySDCore_getCodeSize() LINKABLE;
|
||||
u64 SaltySDCore_findCode(u8* code, size_t size) LINKABLE;
|
||||
}
|
||||
|
||||
#endif // SALTYSD_CORE_H
|
||||
|
|
|
@ -6,14 +6,14 @@
|
|||
#include "useful.h"
|
||||
|
||||
extern "C" {
|
||||
uint64_t SaltySDCore_GetSymbolAddr(void* base, char* name) LINKABLE;
|
||||
uint64_t SaltySDCore_FindSymbol(char* name) LINKABLE;
|
||||
uint64_t SaltySDCore_FindSymbolBuiltin(char* name) LINKABLE;
|
||||
void SaltySDCore_RegisterModule(void* base) LINKABLE;
|
||||
void SaltySDCore_RegisterBuiltinModule(void* base) LINKABLE;
|
||||
void SaltySDCore_DynamicLinkModule(void* base) LINKABLE;
|
||||
void SaltySDCore_ReplaceModuleImport(void* base, char* name, void* new_replace) LINKABLE;
|
||||
void SaltySDCore_ReplaceImport(char* name, void* new_replace) LINKABLE;
|
||||
uint64_t SaltySDCore_GetSymbolAddr(void* base, char* name) LINKABLE;
|
||||
uint64_t SaltySDCore_FindSymbol(char* name) LINKABLE;
|
||||
uint64_t SaltySDCore_FindSymbolBuiltin(char* name) LINKABLE;
|
||||
void SaltySDCore_RegisterModule(void* base) LINKABLE;
|
||||
void SaltySDCore_RegisterBuiltinModule(void* base) LINKABLE;
|
||||
void SaltySDCore_DynamicLinkModule(void* base) LINKABLE;
|
||||
void SaltySDCore_ReplaceModuleImport(void* base, char* name, void* new_replace) LINKABLE;
|
||||
void SaltySDCore_ReplaceImport(char* name, void* new_replace) LINKABLE;
|
||||
}
|
||||
|
||||
#endif // SALTYSD_DYNAMIC_H
|
||||
|
|
36
source/saltysd_helper.cpp
Normal file
36
source/saltysd_helper.cpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
#include <switch.h>
|
||||
|
||||
#include "saltysd_core.h"
|
||||
#include "saltysd_ipc.h"
|
||||
#include "saltysd_dynamic.h"
|
||||
#include "nn_ro.h"
|
||||
|
||||
void (*SaltySD_installed_hook)(char*, u64) = NULL;
|
||||
|
||||
int SaltySD_function_replace(u64 addr, u64 new_func) {
|
||||
if (addr) {
|
||||
SaltySD_Memcpy(addr, (u64) "\x49\x00\x00\x58", 4); // LDR X9, .+8
|
||||
SaltySD_Memcpy(addr+4, (u64) "\x20\x01\x1F\xD6", 4); // BR X9
|
||||
SaltySD_Memcpy(addr+8, (u64) &new_func, 8); // .dword newaddr
|
||||
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int SaltySD_function_replace_sym(char* function_sym, u64 new_func) {
|
||||
u64 addr = SaltySDCore_FindSymbol(function_sym);
|
||||
return SaltySD_function_replace(addr, new_func);
|
||||
}
|
||||
|
||||
void LoadModule(SmashModule *module, void *param_2, void *param_3, unsigned long param_4, int param_5) {
|
||||
nn_ro_LoadModule(module, param_2, param_3, param_4, param_5);
|
||||
if (SaltySD_installed_hook != NULL) {
|
||||
SaltySD_installed_hook((char*)&module->name, (u64)module->module.module->module_base);
|
||||
}
|
||||
}
|
||||
|
||||
void SaltySD_install_nro_hook(u64 LoadModule_thunk_addr, void hook_main(char*, u64)) {
|
||||
SaltySD_installed_hook = hook_main;
|
||||
SaltySD_function_replace(LoadModule_thunk_addr, (u64) LoadModule);
|
||||
}
|
|
@ -2,43 +2,12 @@
|
|||
#define SALTYSD_HELPER_H
|
||||
|
||||
#include <switch.h>
|
||||
#include "saltysd_core.h"
|
||||
#include "saltysd_ipc.h"
|
||||
#include "saltysd_dynamic.h"
|
||||
#include "nn_ro.h"
|
||||
|
||||
#define ANCHOR_REL 0x70ffffc000
|
||||
u64 ANCHOR_ABS;
|
||||
#define IMPORT(x) (x - ANCHOR_REL + ANCHOR_ABS)
|
||||
|
||||
void (*SaltySD_installed_hook)(char*, u64) = NULL;
|
||||
|
||||
int SaltySD_function_replace(u64 addr, u64 new_func) {
|
||||
if (addr) {
|
||||
SaltySD_Memcpy(addr, (u64) "\x49\x00\x00\x58", 4); // LDR X9, .+8
|
||||
SaltySD_Memcpy(addr+4, (u64) "\x20\x01\x1F\xD6", 4); // BR X9
|
||||
SaltySD_Memcpy(addr+8, (u64) &new_func, 8); // .dword newaddr
|
||||
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int SaltySD_function_replace_sym(char* function_sym, u64 new_func) {
|
||||
u64 addr = SaltySDCore_FindSymbol(function_sym);
|
||||
return SaltySD_function_replace(addr, new_func);
|
||||
}
|
||||
|
||||
void LoadModule(SmashModule *module, void *param_2, void *param_3, unsigned long param_4, int param_5) {
|
||||
nn_ro_LoadModule(module, param_2, param_3, param_4, param_5);
|
||||
if(SaltySD_installed_hook != NULL) {
|
||||
SaltySD_installed_hook((char*)&module->name, (u64)module->module.module->module_base);
|
||||
}
|
||||
}
|
||||
|
||||
void SaltySD_install_nro_hook(u64 LoadModule_thunk_addr, void hook_main(char*, u64)) {
|
||||
SaltySD_installed_hook = hook_main;
|
||||
SaltySD_function_replace(LoadModule_thunk_addr, (u64) LoadModule);
|
||||
}
|
||||
int SaltySD_function_replace(u64 addr, u64 new_func);
|
||||
int SaltySD_function_replace_sym(char* function_sym, u64 new_func);
|
||||
|
||||
#endif // SALTYSD_HELPER_H
|
||||
|
|
|
@ -6,14 +6,14 @@
|
|||
#include "useful.h"
|
||||
|
||||
extern "C" {
|
||||
void SaltySD_Init() LINKABLE;
|
||||
Result SaltySD_Deinit() LINKABLE;
|
||||
Result SaltySD_Term() LINKABLE;
|
||||
Result SaltySD_Restore() LINKABLE;
|
||||
Result SaltySD_LoadELF(u64 heap, u64* elf_addr, u64* elf_size, char* name) LINKABLE;
|
||||
Result SaltySD_Memcpy(u64 to, u64 from, u64 size) LINKABLE;
|
||||
Result SaltySD_GetSDCard(Handle *retrieve) LINKABLE;
|
||||
Result SaltySD_printf(const char* format, ...) LINKABLE;
|
||||
void SaltySD_Init() LINKABLE;
|
||||
Result SaltySD_Deinit() LINKABLE;
|
||||
Result SaltySD_Term() LINKABLE;
|
||||
Result SaltySD_Restore() LINKABLE;
|
||||
Result SaltySD_LoadELF(u64 heap, u64* elf_addr, u64* elf_size, char* name) LINKABLE;
|
||||
Result SaltySD_Memcpy(u64 to, u64 from, u64 size) LINKABLE;
|
||||
Result SaltySD_GetSDCard(Handle *retrieve) LINKABLE;
|
||||
Result SaltySD_printf(const char* format, ...) LINKABLE;
|
||||
}
|
||||
|
||||
#endif //SALTYSD_IPC_H
|
||||
|
|
|
@ -3,11 +3,10 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include "crc32.h"
|
||||
#include "useful.h"
|
||||
|
||||
#include "l2c.hpp"
|
||||
#include "l2c_imports.hpp"
|
||||
#include "acmd_wrapper.hpp"
|
||||
#include "lua_helper.hpp"
|
||||
|
||||
#include "raygun_printer.hpp"
|
||||
|
||||
|
@ -36,99 +35,84 @@ void replace_scripts(L2CAgent* l2c_agent, u8 category, int kind) {
|
|||
}
|
||||
|
||||
u64 appeal_lw_replace(L2CAgent* l2c_agent, void* variadic) {
|
||||
ACMD acmd = ACMD(l2c_agent);
|
||||
ACMD acmd = ACMD(l2c_agent);
|
||||
|
||||
acmd.frame(1);
|
||||
if (acmd.is_excute()) {
|
||||
TOGGLE_STATE = (TOGGLE_STATE + 1) % NUM_TOGGLE_STATES;
|
||||
if (TOGGLE_STATE == MASH_AIRDODGE)
|
||||
print_string(acmd.module_accessor, "MASH\nAIRDODGE");
|
||||
else if (TOGGLE_STATE == MASH_JUMP)
|
||||
print_string(acmd.module_accessor, "MASH\nJUMP");
|
||||
else
|
||||
print_string(acmd.module_accessor, "NONE");
|
||||
}
|
||||
acmd.frame(1);
|
||||
if (acmd.is_excute()) {
|
||||
TOGGLE_STATE = (TOGGLE_STATE + 1) % NUM_TOGGLE_STATES;
|
||||
if (TOGGLE_STATE == MASH_AIRDODGE)
|
||||
print_string(acmd.module_accessor, "MASH\nAIRDODGE");
|
||||
else if (TOGGLE_STATE == MASH_JUMP)
|
||||
print_string(acmd.module_accessor, "MASH\nJUMP");
|
||||
else
|
||||
print_string(acmd.module_accessor, "NONE");
|
||||
}
|
||||
|
||||
return 0;
|
||||
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()) {
|
||||
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()) {
|
||||
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()) {
|
||||
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]);
|
||||
}
|
||||
acmd.frame(1);
|
||||
if (acmd.is_excute()) {
|
||||
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]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// AnimCMD replacement function
|
||||
u64 shine_replace(L2CAgent* l2c_agent, void* variadic) {
|
||||
ACMD acmd = ACMD(l2c_agent);
|
||||
|
||||
acmd.frame(1);
|
||||
if (acmd.is_excute()) {
|
||||
acmd.ATTACK(0, 0, hash40("top"), 10.0, 10, 32, 0, 66, 7.5, 0, 6.5,
|
||||
// 0, 0, 0, //L2C_voids: no X2, Y2, Z2
|
||||
0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 63, 31, 0,
|
||||
0x13462FCFE4LL, 2, 7, 25);
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
return 0;
|
||||
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;
|
||||
}
|
||||
|
||||
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 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;
|
||||
}
|
||||
|
|
|
@ -21,4 +21,4 @@ int DI_STATE = 0;
|
|||
int TOGGLE_STATE = 0;
|
||||
#define NUM_TOGGLE_STATES 3
|
||||
|
||||
#endif // TAUNT_TOGGLES_H
|
||||
#endif // TAUNT_TOGGLES_H
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "l2c.hpp"
|
||||
#include "saltysd_helper.hpp"
|
||||
#include "useful.h"
|
||||
#include "l2c_imports.hpp"
|
||||
#include "saltysd_helper.hpp"
|
||||
#include "acmd_imports.hpp"
|
||||
#include "taunt_toggles.h"
|
||||
#include "raygun_printer.hpp"
|
||||
|
@ -12,130 +12,122 @@ 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;
|
||||
}
|
||||
|
||||
void perform_jump(u64 module_accessor) {
|
||||
int jump_count = WorkModule::get_int(module_accessor, FIGHTER_INSTANCE_WORK_ID_INT_JUMP_COUNT);
|
||||
int max_jump_count = WorkModule::get_int(module_accessor, FIGHTER_INSTANCE_WORK_ID_INT_JUMP_COUNT_MAX);
|
||||
if (jump_count < max_jump_count) {
|
||||
if (StatusModule::situation_kind(module_accessor) == SITUATION_KIND_AIR) {
|
||||
if (WorkModule::get_param_int(module_accessor, 0xB99CC3FBCLL, 0) == FIGHTER_JUMP_AERIAL_TYPE_NORMAL)
|
||||
StatusModule::change_status_request_from_script(module_accessor, FIGHTER_STATUS_KIND_JUMP_AERIAL, 1);
|
||||
else
|
||||
StatusModule::change_status_request_from_script(module_accessor, FIGHTER_STATUS_KIND_FLY, 1);
|
||||
} else if (StatusModule::situation_kind(module_accessor) == SITUATION_KIND_GROUND)
|
||||
StatusModule::change_status_request_from_script(module_accessor, FIGHTER_STATUS_KIND_JUMP_SQUAT, 1);
|
||||
WorkModule::inc_int(module_accessor, FIGHTER_INSTANCE_WORK_ID_INT_JUMP_COUNT);
|
||||
}
|
||||
int jump_count = WorkModule::get_int(module_accessor, FIGHTER_INSTANCE_WORK_ID_INT_JUMP_COUNT);
|
||||
int max_jump_count = WorkModule::get_int(module_accessor, FIGHTER_INSTANCE_WORK_ID_INT_JUMP_COUNT_MAX);
|
||||
if (jump_count < max_jump_count) {
|
||||
if (StatusModule::situation_kind(module_accessor) == SITUATION_KIND_AIR) {
|
||||
if (WorkModule::get_param_int(module_accessor, 0xB99CC3FBCLL, 0) == FIGHTER_JUMP_AERIAL_TYPE_NORMAL)
|
||||
StatusModule::change_status_request_from_script(module_accessor, FIGHTER_STATUS_KIND_JUMP_AERIAL, 1);
|
||||
else
|
||||
StatusModule::change_status_request_from_script(module_accessor, FIGHTER_STATUS_KIND_FLY, 1);
|
||||
} else if (StatusModule::situation_kind(module_accessor) == SITUATION_KIND_GROUND) {
|
||||
StatusModule::change_status_request_from_script(module_accessor, FIGHTER_STATUS_KIND_JUMP_SQUAT, 1);
|
||||
}
|
||||
WorkModule::inc_int(module_accessor, FIGHTER_INSTANCE_WORK_ID_INT_JUMP_COUNT);
|
||||
}
|
||||
}
|
||||
|
||||
namespace app::lua_bind::WorkModule {
|
||||
// Force option out of hitstun
|
||||
u64 enable_transition_term_group_replace(u64 module_accessor, int transition_group) {
|
||||
if (is_training_mode() && is_operation_cpu(module_accessor)) {
|
||||
if (is_in_hitstun(module_accessor)) {
|
||||
// Airdodge
|
||||
if (TOGGLE_STATE == MASH_AIRDODGE) {
|
||||
if (transition_group == FIGHTER_STATUS_TRANSITION_GROUP_CHK_AIR_ESCAPE)
|
||||
StatusModule::change_status_request_from_script(module_accessor, FIGHTER_STATUS_KIND_ESCAPE_AIR, 1);
|
||||
}
|
||||
// Jump
|
||||
else if (TOGGLE_STATE == MASH_JUMP) {
|
||||
if (transition_group == FIGHTER_STATUS_TRANSITION_GROUP_CHK_AIR_JUMP_AERIAL)
|
||||
perform_jump(module_accessor);
|
||||
else if (transition_group == FIGHTER_STATUS_TRANSITION_GROUP_CHK_GROUND_JUMP)
|
||||
perform_jump(module_accessor);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Force option out of hitstun
|
||||
u64 enable_transition_term_group_replace(u64 module_accessor, int transition_group) {
|
||||
if (is_training_mode() && is_operation_cpu(module_accessor)) {
|
||||
if (is_in_hitstun(module_accessor)) {
|
||||
if (TOGGLE_STATE == MASH_AIRDODGE) { // airdodge
|
||||
if (transition_group == FIGHTER_STATUS_TRANSITION_GROUP_CHK_AIR_ESCAPE)
|
||||
StatusModule::change_status_request_from_script(module_accessor, FIGHTER_STATUS_KIND_ESCAPE_AIR, 1);
|
||||
} else if (TOGGLE_STATE == MASH_JUMP) { // jump
|
||||
if (transition_group == FIGHTER_STATUS_TRANSITION_GROUP_CHK_AIR_JUMP_AERIAL)
|
||||
perform_jump(module_accessor);
|
||||
else if (transition_group == FIGHTER_STATUS_TRANSITION_GROUP_CHK_GROUND_JUMP)
|
||||
perform_jump(module_accessor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// call original WorkModule::enable_transition_term_group_impl
|
||||
u64 work_module = load_module(module_accessor, 0x50);
|
||||
u64 (*enable_transition_term_group)(u64, u64) = (u64(*)(u64, u64))(load_module_impl(work_module, 0x140));
|
||||
// call original WorkModule::enable_transition_term_group_impl
|
||||
u64 work_module = load_module(module_accessor, 0x50);
|
||||
u64 (*enable_transition_term_group)(u64, u64) = (u64(*)(u64, u64))(load_module_impl(work_module, 0x140));
|
||||
|
||||
return enable_transition_term_group(work_module, transition_group);
|
||||
}
|
||||
return enable_transition_term_group(work_module, transition_group);
|
||||
}
|
||||
|
||||
// Force DI
|
||||
float get_float_replace(u64 module_accessor, int var) {
|
||||
if (is_training_mode() && is_operation_cpu(module_accessor)) {
|
||||
if (is_in_hitstun(module_accessor)) {
|
||||
if (DI_STATE != NONE) {
|
||||
float angle = (DI_STATE - 1) * M_PI / 4.0;
|
||||
// Force DI
|
||||
float get_float_replace(u64 module_accessor, int var) {
|
||||
if (is_training_mode() && is_operation_cpu(module_accessor)) {
|
||||
if (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;
|
||||
}
|
||||
// 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 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (var == FIGHTER_STATUS_DAMAGE_WORK_FLOAT_VECOR_CORRECT_STICK_Y)
|
||||
return sin(angle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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));
|
||||
// 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));
|
||||
|
||||
return get_float(work_module, var);
|
||||
}
|
||||
return get_float(work_module, var);
|
||||
}
|
||||
}
|
||||
|
||||
namespace app::lua_bind::MotionModule {
|
||||
void change_motion_replace(u64 module_accessor, u64 motion_kind, float start_frame, float frame_speed_mult, bool unk1, float unk2, bool unk3, bool unk4) {
|
||||
|
||||
u64 curr_motion_kind = MotionModule::motion_kind(module_accessor);
|
||||
if ((curr_motion_kind == hash40("damage_air_1") ||
|
||||
curr_motion_kind == hash40("damage_air_2") ||
|
||||
curr_motion_kind == hash40("damage_air_3")) && motion_kind == hash40("fall")) {
|
||||
if (is_training_mode() && is_operation_cpu(module_accessor)) {
|
||||
// Airdodge
|
||||
if (TOGGLE_STATE == MASH_AIRDODGE)
|
||||
StatusModule::change_status_request_from_script(module_accessor, FIGHTER_STATUS_KIND_ESCAPE_AIR, 1);
|
||||
// Jump
|
||||
else if (TOGGLE_STATE == MASH_JUMP)
|
||||
perform_jump(module_accessor);
|
||||
}
|
||||
}
|
||||
void change_motion_replace(u64 module_accessor, u64 motion_kind, float start_frame, float frame_speed_mult, bool unk1, float unk2, bool unk3, bool unk4) {
|
||||
u64 curr_motion_kind = MotionModule::motion_kind(module_accessor);
|
||||
if ((curr_motion_kind == hash40("damage_air_1") ||
|
||||
curr_motion_kind == hash40("damage_air_2") ||
|
||||
curr_motion_kind == hash40("damage_air_3")) && motion_kind == hash40("fall")) {
|
||||
if (is_training_mode() && is_operation_cpu(module_accessor)) {
|
||||
if (TOGGLE_STATE == MASH_AIRDODGE) // airdodge
|
||||
StatusModule::change_status_request_from_script(module_accessor, FIGHTER_STATUS_KIND_ESCAPE_AIR, 1);
|
||||
else if (TOGGLE_STATE == MASH_JUMP) // jump
|
||||
perform_jump(module_accessor);
|
||||
}
|
||||
}
|
||||
|
||||
// call original
|
||||
u64 motion_module = load_module(module_accessor, 0x88);
|
||||
void (*change_motion)(u64, u64, float, float, bool, float, bool, bool) =
|
||||
(void (*)(u64, u64, float, float, bool, float, bool, bool)) load_module_impl(motion_module, 0xD8);
|
||||
// call original
|
||||
u64 motion_module = load_module(module_accessor, 0x88);
|
||||
void (*change_motion)(u64, u64, float, float, bool, float, bool, bool) =
|
||||
(void (*)(u64, u64, float, float, bool, float, bool, bool)) load_module_impl(motion_module, 0xD8);
|
||||
|
||||
change_motion(motion_module, motion_kind, start_frame, frame_speed_mult, unk1, unk2, unk3, unk4);
|
||||
}
|
||||
change_motion(motion_module, motion_kind, start_frame, frame_speed_mult, unk1, unk2, unk3, unk4);
|
||||
}
|
||||
}
|
||||
|
||||
void training_mods_main() {
|
||||
fighter_manager_addr = SaltySDCore_FindSymbol("_ZN3lib9SingletonIN3app14FighterManagerEE9instance_E");
|
||||
|
||||
SaltySD_function_replace_sym(
|
||||
"_ZN3app8lua_bind45WorkModule__enable_transition_term_group_implEPNS_26BattleObjectModuleAccessorEi",
|
||||
(u64)&WorkModule::enable_transition_term_group_replace);
|
||||
|
||||
SaltySD_function_replace_sym(
|
||||
"_ZN3app8lua_bind26WorkModule__get_float_implEPNS_26BattleObjectModuleAccessorEi",
|
||||
(u64)&WorkModule::get_float_replace);
|
||||
|
||||
SaltySD_function_replace_sym(
|
||||
"_ZN3app8lua_bind32MotionModule__change_motion_implEPNS_26BattleObjectModuleAccessorEN3phx6Hash40Effbfbb",
|
||||
(u64)&MotionModule::change_motion_replace);
|
||||
}
|
||||
fighter_manager_addr = SaltySDCore_FindSymbol("_ZN3lib9SingletonIN3app14FighterManagerEE9instance_E");
|
||||
SaltySD_function_replace_sym(
|
||||
"_ZN3app8lua_bind45WorkModule__enable_transition_term_group_implEPNS_26BattleObjectModuleAccessorEi",
|
||||
(u64)&WorkModule::enable_transition_term_group_replace);
|
||||
SaltySD_function_replace_sym(
|
||||
"_ZN3app8lua_bind26WorkModule__get_float_implEPNS_26BattleObjectModuleAccessorEi",
|
||||
(u64)&WorkModule::get_float_replace);
|
||||
SaltySD_function_replace_sym(
|
||||
"_ZN3app8lua_bind32MotionModule__change_motion_implEPNS_26BattleObjectModuleAccessorEN3phx6Hash40Effbfbb",
|
||||
(u64)&MotionModule::change_motion_replace);
|
||||
}
|
||||
|
|
|
@ -7,8 +7,20 @@
|
|||
|
||||
#define LINKABLE __attribute__ ((weak))
|
||||
|
||||
#define debug_log(...) \
|
||||
{char log_buf[0x200]; snprintf(log_buf, 0x200, __VA_ARGS__); \
|
||||
svcOutputDebugString(log_buf, strlen(log_buf));}
|
||||
|
||||
#define LOAD64 *(u64 *)
|
||||
|
||||
#define debug_log(...) {\
|
||||
char log_buf[0x200]; snprintf(log_buf, 0x200, __VA_ARGS__); \
|
||||
svcOutputDebugString(log_buf, strlen(log_buf)); }
|
||||
|
||||
typedef struct Hash40 {
|
||||
uint64_t hash : 40;
|
||||
} Hash40;
|
||||
|
||||
typedef struct Vector3f {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
} Vector3f;
|
||||
|
||||
#endif // USEFUL_H
|
||||
|
|
35
source/useful_visual.cpp
Normal file
35
source/useful_visual.cpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
#include "useful_visual.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "useful.h"
|
||||
|
||||
float round_to(float val, float align) {
|
||||
return roundf(val / align) * align;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
float lerp_bounded(float min, float max, float 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);
|
||||
}
|
||||
|
||||
Vector3f color_lerp(Vector3f min_color, Vector3f max_color, float t, float gamma) {
|
||||
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)
|
||||
};
|
||||
}
|
31
source/useful_visual.h
Normal file
31
source/useful_visual.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#ifndef USEFUL_VISUAL_H
|
||||
#define USEFUL_VISUAL_H
|
||||
|
||||
#include "useful.h"
|
||||
/**
|
||||
* Rounds a number to the nearest multiple of another number.
|
||||
*/
|
||||
float round_to(float val, float align);
|
||||
|
||||
/**
|
||||
* Linearly interpolates between two numbers, without bounds checking.
|
||||
*/
|
||||
float lerp(float min, float max, float t);
|
||||
float unlerp(float min, float max, float val);
|
||||
/**
|
||||
* Linearly interpolates between two numbers, with bounds checking.
|
||||
*/
|
||||
float lerp_bounded(float min, float max, float t);
|
||||
float unlerp_bounded(float min, float max, float 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
|
||||
* - 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
|
||||
*/
|
||||
Vector3f color_lerp(Vector3f min_color, Vector3f max_color, float t, float gamma = 2.0f);
|
||||
|
||||
#endif // USEFUL_VISUAL_H
|
Loading…
Add table
Reference in a new issue