Configurable multi-animation and attack speed

This commit is contained in:
harlanx 2022-08-20 18:29:22 +08:00
parent dfb5fb5d1a
commit 24e030587b
2 changed files with 65 additions and 19 deletions

View File

@ -14,6 +14,12 @@ namespace cheat::feature
app::AnimatorStateInfo processStateInfo, app::MoleMole_VCAnimatorEvent_MoleMole_VCAnimatorEvent_TriggerMode__Enum mode, MethodInfo* method); app::AnimatorStateInfo processStateInfo, app::MoleMole_VCAnimatorEvent_MoleMole_VCAnimatorEvent_TriggerMode__Enum mode, MethodInfo* method);
static void LCBaseCombat_FireBeingHitEvent_Hook(app::LCBaseCombat* __this, uint32_t attackeeRuntimeID, app::AttackResult* attackResult, MethodInfo* method); static void LCBaseCombat_FireBeingHitEvent_Hook(app::LCBaseCombat* __this, uint32_t attackeeRuntimeID, app::AttackResult* attackResult, MethodInfo* method);
static int32_t attackTags[] = {
1638193991, // Normal and Charged
1498431743, // Plunge
-584054938, 0, // Skill, Burst and Charged Bow Release
};
RapidFire::RapidFire() : Feature(), RapidFire::RapidFire() : Feature(),
NF(f_Enabled, "Attack Multiplier", "RapidFire", false), NF(f_Enabled, "Attack Multiplier", "RapidFire", false),
NF(f_MultiHit, "Multi-hit", "RapidFire", false), NF(f_MultiHit, "Multi-hit", "RapidFire", false),
@ -24,7 +30,12 @@ namespace cheat::feature
NF(f_maxMultiplier, "Max Multiplier", "RapidFire", 3), NF(f_maxMultiplier, "Max Multiplier", "RapidFire", 3),
NF(f_MultiTarget, "Multi-target", "RapidFire", false), NF(f_MultiTarget, "Multi-target", "RapidFire", false),
NF(f_MultiTargetRadius, "Multi-target Radius", "RapidFire", 20.0f), NF(f_MultiTargetRadius, "Multi-target Radius", "RapidFire", 20.0f),
NF(f_MultiAnimation, "Multi-animation", "RapidFire", false) NF(f_MultiAnimation, "Multi-animation", "RapidFire", false),
NF(f_AnimationMultiplier, "Animation Multiplier", "RapidFire", 100),
NF(f_AnimationState, "Animation State", "RapidFire", 0.5f),
NF(f_AttackSpeed, "Attack Speed", "RapidFire", false),
NF(f_SpeedMultiplier, "Speed Multiplier", "RapidFire", 1.5f),
animationCounter(1)
{ {
// HookManager::install(app::MoleMole_LCBaseCombat_DoHitEntity, LCBaseCombat_DoHitEntity_Hook); -- Looks like FireBeingHitEvent is superior to this. // HookManager::install(app::MoleMole_LCBaseCombat_DoHitEntity, LCBaseCombat_DoHitEntity_Hook); -- Looks like FireBeingHitEvent is superior to this.
HookManager::install(app::MoleMole_VCAnimatorEvent_HandleProcessItem, VCAnimatorEvent_HandleProcessItem_Hook); HookManager::install(app::MoleMole_VCAnimatorEvent_HandleProcessItem, VCAnimatorEvent_HandleProcessItem_Hook);
@ -85,15 +96,23 @@ namespace cheat::feature
ConfigWidget("Multi-animation", f_MultiAnimation, "Enables multi-animation attacks.\n" \ ConfigWidget("Multi-animation", f_MultiAnimation, "Enables multi-animation attacks.\n" \
"Do keep in mind that the character's audio will also be spammed."); "Do keep in mind that the character's audio will also be spammed.");
ConfigWidget("Animation Multiplier", f_AnimationMultiplier, 1, 1, 150, "Configure to how many times it will update the animation state.\n" \
"Results can vary alongside Animation State");
ConfigWidget("Animation State", f_AnimationState, 0.01f, 0.f, 2.f, "Animation state to replay.\n"\
"Results can vary alongside Animation Multiplier");
ConfigWidget("Attack Speed", f_AttackSpeed, "Enables fast animation attacks.\n");
ConfigWidget("Speed Multiplier", f_SpeedMultiplier, 0.1f, 1.0f, 5.0f, "Attack speed multiplier.");
} }
bool RapidFire::NeedStatusDraw() const bool RapidFire::NeedStatusDraw() const
{ {
return f_Enabled && (f_MultiHit || f_MultiTarget || f_MultiAnimation); return (f_Enabled && (f_MultiHit || f_MultiTarget)) || f_MultiAnimation || f_AttackSpeed;
} }
void RapidFire::DrawStatus() void RapidFire::DrawStatus()
{ {
if (f_Enabled) {
ImGui::Text("Rapid Fire:");
if (f_MultiHit) if (f_MultiHit)
{ {
if (f_Randomize) if (f_Randomize)
@ -105,9 +124,12 @@ namespace cheat::feature
} }
if (f_MultiTarget) if (f_MultiTarget)
ImGui::Text("Multi-Target [%.01fm]", f_MultiTargetRadius.value()); ImGui::Text("Multi-Target [%.01fm]", f_MultiTargetRadius.value());
}
if (f_MultiAnimation) if (f_MultiAnimation)
ImGui::Text("Multi-Animation"); ImGui::Text("Multi-Animation [%d|%0.2f]", f_AnimationMultiplier.value(), f_AnimationState.value());
if(f_AttackSpeed)
ImGui::Text("Attack Speed [%0.1f]", f_SpeedMultiplier.value());
} }
RapidFire& RapidFire::GetInstance() RapidFire& RapidFire::GetInstance()
@ -116,7 +138,6 @@ namespace cheat::feature
return instance; return instance;
} }
int RapidFire::CalcCountToKill(float attackDamage, uint32_t targetID) int RapidFire::CalcCountToKill(float attackDamage, uint32_t targetID)
{ {
if (attackDamage == 0) if (attackDamage == 0)
@ -203,6 +224,7 @@ namespace cheat::feature
return false; return false;
auto& manager = game::EntityManager::instance(); auto& manager = game::EntityManager::instance();
auto patterID = manager.avatar()->combat()->monitor;
auto avatarID = manager.avatar()->raw()->fields._configID_k__BackingField; auto avatarID = manager.avatar()->raw()->fields._configID_k__BackingField;
auto attackerID = attacker.raw()->fields._configID_k__BackingField; auto attackerID = attacker.raw()->fields._configID_k__BackingField;
// LOG_DEBUG("configID = %d", attackerID); // LOG_DEBUG("configID = %d", attackerID);
@ -329,11 +351,30 @@ namespace cheat::feature
{ {
auto attacker = game::Entity(__this->fields._._._entity); auto attacker = game::Entity(__this->fields._._._entity);
RapidFire& rapidFire = RapidFire::GetInstance(); RapidFire& rapidFire = RapidFire::GetInstance();
bool isAttackAnimation = std::any_of(std::begin(attackTags), std::end(attackTags),
[&](uint32_t tag) { return processStateInfo.m_Tag == tag; });
bool isAttacking = IsAttackByAvatar(attacker) && isAttackAnimation;
if (rapidFire.f_MultiAnimation && IsAttackByAvatar(attacker)) if (rapidFire.f_MultiAnimation && isAttacking)
processItem->fields.lastTime = 0; {
// Set counter back to 1 when any new attack animation is invoked
if (processStateInfo.m_NormalizedTime <= 0.01f)
rapidFire.animationCounter = 1;
if (rapidFire.animationCounter <= rapidFire.f_AnimationMultiplier)
{
// Can be configured up to 1.0 but 0.1 to 0.9 you can barely notice the difference
// So 0 - 0.2 is enough.
processItem->fields.lastTime = (rapidFire.f_AnimationState / 10);
rapidFire.animationCounter++;
}
}
if (rapidFire.f_AttackSpeed && isAttacking)
app::Animator_set_speed(attacker.animator(), rapidFire.f_SpeedMultiplier, nullptr);
else
app::Animator_set_speed(attacker.animator(), processStateInfo.m_SpeedMultiplier, nullptr);
CALL_ORIGIN(VCAnimatorEvent_HandleProcessItem_Hook, __this, processItem, processStateInfo, mode, method); CALL_ORIGIN(VCAnimatorEvent_HandleProcessItem_Hook, __this, processItem, processStateInfo, mode, method);
} }
} }

View File

@ -6,7 +6,6 @@
namespace cheat::feature namespace cheat::feature
{ {
class RapidFire : public Feature class RapidFire : public Feature
{ {
public: public:
@ -20,6 +19,11 @@ namespace cheat::feature
config::Field<config::Toggle<Hotkey>> f_MultiTarget; config::Field<config::Toggle<Hotkey>> f_MultiTarget;
config::Field<float> f_MultiTargetRadius; config::Field<float> f_MultiTargetRadius;
config::Field<config::Toggle<Hotkey>> f_MultiAnimation; config::Field<config::Toggle<Hotkey>> f_MultiAnimation;
config::Field<int> f_AnimationMultiplier;
config::Field<float> f_AnimationState;
config::Field<config::Toggle<Hotkey>> f_AttackSpeed;
config::Field<float> f_SpeedMultiplier;
uint32_t animationCounter;
static RapidFire& GetInstance(); static RapidFire& GetInstance();
@ -36,3 +40,4 @@ namespace cheat::feature
}; };
} }