Merge pull request #665 from harlanx/configurable_animation_and_attack_speed

Configurable multi-animation and attack speed
This commit is contained in:
Joaquin 2022-09-13 01:43:05 -06:00 committed by GitHub
commit 43a0f4493d
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);
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(),
NF(f_Enabled, "Attack Multiplier", "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_MultiTarget, "Multi-target", "RapidFire", false),
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_VCAnimatorEvent_HandleProcessItem, VCAnimatorEvent_HandleProcessItem_Hook);
@ -85,29 +96,40 @@ namespace cheat::feature
ConfigWidget("Multi-animation", f_MultiAnimation, "Enables multi-animation attacks.\n" \
"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
{
return f_Enabled && (f_MultiHit || f_MultiTarget || f_MultiAnimation);
return (f_Enabled && (f_MultiHit || f_MultiTarget)) || f_MultiAnimation || f_AttackSpeed;
}
void RapidFire::DrawStatus()
{
if (f_MultiHit)
{
if (f_Randomize)
ImGui::Text("Multi-Hit Random[%d|%d]", f_minMultiplier.value(), f_maxMultiplier.value());
else if (f_OnePunch)
ImGui::Text("Multi-Hit [OnePunch]");
else
ImGui::Text("Multi-Hit [%d]", f_Multiplier.value());
if (f_Enabled) {
ImGui::Text("Rapid Fire:");
if (f_MultiHit)
{
if (f_Randomize)
ImGui::Text("Multi-Hit Random[%d|%d]", f_minMultiplier.value(), f_maxMultiplier.value());
else if (f_OnePunch)
ImGui::Text("Multi-Hit [OnePunch]");
else
ImGui::Text("Multi-Hit [%d]", f_Multiplier.value());
}
if (f_MultiTarget)
ImGui::Text("Multi-Target [%.01fm]", f_MultiTargetRadius.value());
}
if (f_MultiTarget)
ImGui::Text("Multi-Target [%.01fm]", f_MultiTargetRadius.value());
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()
@ -116,7 +138,6 @@ namespace cheat::feature
return instance;
}
int RapidFire::CalcCountToKill(float attackDamage, uint32_t targetID)
{
if (attackDamage == 0)
@ -203,6 +224,7 @@ namespace cheat::feature
return false;
auto& manager = game::EntityManager::instance();
auto patterID = manager.avatar()->combat()->monitor;
auto avatarID = manager.avatar()->raw()->fields._configID_k__BackingField;
auto attackerID = attacker.raw()->fields._configID_k__BackingField;
// LOG_DEBUG("configID = %d", attackerID);
@ -329,11 +351,30 @@ namespace cheat::feature
{
auto attacker = game::Entity(__this->fields._._._entity);
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))
processItem->fields.lastTime = 0;
if (rapidFire.f_MultiAnimation && isAttacking)
{
// 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);
}
}
}

View File

@ -6,7 +6,6 @@
namespace cheat::feature
{
class RapidFire : public Feature
{
public:
@ -20,6 +19,11 @@ namespace cheat::feature
config::Field<config::Toggle<Hotkey>> f_MultiTarget;
config::Field<float> f_MultiTargetRadius;
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();
@ -36,3 +40,4 @@ namespace cheat::feature
};
}