Files
Cielonos/Assets/Scripts/MainGame/Characters/Automata/Enemies/C1_Axe.cs
SoulliesOfficial 9a9e48f8a5
2026-06-27 12:52:03 -04:00

244 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.Generic;
using Cielonos.MainGame.AttackArea;
using Cielonos.MainGame.Buffs.Character;
using Lean.Pool;
using SLSUtilities.FunctionalAnimation;
using SLSUtilities.General;
using SLSUtilities.WwiseAssistance;
using UnityEngine;
namespace Cielonos.MainGame.Characters
{
public partial class C1_Axe : Enemy
{
protected override void InitializeSubmodules()
{
base.InitializeSubmodules();
// Boss 怯战惩罚机制5秒未受玩家攻击且未被玩家格挡每秒快速恢复20点能量
new CowardicePenalty().Apply(this);
eventSm.onGetBreakthrough.Add("GetBreakthrough_Weak", new PrioritizedAction<AttackAreaBase>(attackArea =>
{
new Weak(5).Apply(this);
GetHit(Breakthrough.Type.Forced, out _, DisruptionType.ForcedExternal, funcAnimName: "GetBreakthrough");
movementSc.impulseSm.ApplyKnockback(-transform.forward, 10f, 1f, null, true);
}));
}
}
public partial class C1_Axe
{
private void FAPF_GenerateSlash(RuntimeFuncAnim rtFuncAnim)
{
CustomFunction.PC_StringString p = rtFuncAnim.GetParams<CustomFunction.PC_StringString>();
GenerateSlash(p.str0, attackData[p.str1]);
}
private void FAPF_GenerateSmash(RuntimeFuncAnim rtFuncAnim)
{
CustomFunction.PC_StringString p = rtFuncAnim.GetParams<CustomFunction.PC_StringString>();
GenerateSmash(p.str0, attackData[p.str1]);
}
private void FAPF_GenerateTripleSmashes(RuntimeFuncAnim rtFuncAnim)
{
CustomFunction.PC_StringString p = rtFuncAnim.GetParams<CustomFunction.PC_StringString>();
float timeInterval = 0.2f;
Vector3 fwd = transform.forward;
for (int i = 0; i < 3; i++)
{
float delay = i * timeInterval;
int index = i;
selfTimeSm.AddLocalTimer(delay, () => GenerateSmash(p.str0, attackData[p.str1], fwd * (index * 5f), fwd));
}
}
private void FAPF_GenerateWhirlWind(RuntimeFuncAnim rtFuncAnim)
{
CustomFunction.PC_StringStringFloat p = rtFuncAnim.GetParams<CustomFunction.PC_StringStringFloat>();
GenerateWhirlWind(p.str0, attackData[p.str1], p.float0);
}
private void FAPF_GenerateMeteorStorm(RuntimeFuncAnim rtFuncAnim)
{
CustomFunction.PC_StringStringFloat p = rtFuncAnim.GetParams<CustomFunction.PC_StringStringFloat>();
string vfxName = p.str0;
string attackKey = p.str1;
float radius = p.float0;
AttackUnit attackUnit = attackData[attackKey];
for (int i = 0; i < 15; i++)
{
float delay = i * 1.0f; // 每秒生成一个,持续 15 秒
int index = i;
selfTimeSm.AddLocalTimer(delay, () =>
{
// 动态获取玩家当前状态
if (player == null || player.statusSm.isDead) return;
Vector3 targetPos;
if ((index + 2) % 5 == 0) // 每5个陨石中的第4个直接落在玩家当前位置增加难度
{
targetPos = player.transform.position;
}
else if ((index + 1) % 5 == 0) //每5个陨石的第5个预测玩家位置增加难度
{
targetPos = PredictPlayerPosition(0.85f);
}
else
{
// 随机在玩家周身一定半径内
Vector2 randomOffset = Random.insideUnitCircle * radius;
targetPos = player.transform.position + new Vector3(randomOffset.x, 0f, randomOffset.y);
}
// 利用 NavMesh 进行投影对齐,防止指示器浮空或生成在墙壁外部
if (UnityEngine.AI.NavMesh.SamplePosition(targetPos, out UnityEngine.AI.NavMeshHit hit, radius, UnityEngine.AI.NavMesh.AllAreas))
{
targetPos = hit.position;
}
GenerateMeteor(vfxName, attackUnit, targetPos);
// 额外生成第二枚陨石,避免与第一枚重合
List<Vector3> extraMeteors = AttackAreaDistributionHelper.GenerateNonOverlappingInCircle(
player.transform.position, radius, 4f, 1, new List<Vector3> { targetPos });
foreach (Vector3 pos in extraMeteors)
{
GenerateMeteor(vfxName, attackUnit, pos);
}
});
}
}
private void FAPF_GenerateMovingSlashes(RuntimeFuncAnim rtFuncAnim)
{
CustomFunction.PC_StringStringInt p = rtFuncAnim.GetParams<CustomFunction.PC_StringStringInt>();
string vfxName = p.str0;
string attackKey = p.str1;
int count = p.int0;
if (count <= 0) return;
Vector3 baseDir = transform.forward;
if (player != null && !player.statusSm.isDead)
{
baseDir = (player.transform.position - transform.position).normalized;
baseDir.y = 0;
if (baseDir == Vector3.zero) baseDir = transform.forward;
baseDir.Normalize();
}
for (int i = 0; i < count; i++)
{
float angle = (i - (count - 1) / 2.0f) * 30f;
Vector3 slashDir = Quaternion.Euler(0, angle, 0) * baseDir;
Vector3 upFix = Vector3.up * 1.5f;
GenerateMovingSlash(vfxName, attackData[attackKey], transform.position + upFix + slashDir * 2f, slashDir, 10f, 10f);
}
}
}
public partial class C1_Axe
{
private NormalArea GenerateSlash(string vfxName, AttackUnit attackUnit)
{
NormalArea slash = vfxData.SpawnVFX(vfxName, this).GetComponentInChildren<NormalArea>();
slash.Initialize<NormalArea>(this, Fraction.Player)
.SetAttackSubmodule<NormalArea>(attackUnit)
.SetTimeSubmodule<NormalArea>(3f)
.SetHitSubmodule<NormalArea>();
slash.SetImpulseSubmodule().WithRepulsion(3);
slash.hitSm.AddHitSound(AK.EVENTS.C1_AXE_SWINGHIT);
return slash;
}
private NormalArea GenerateSmash(string vfxName, AttackUnit attackUnit,
Vector3 positionOffset = default, Vector3 force = default)
{
NormalArea slash = vfxData.SpawnVFX(vfxName, this).GetComponentInChildren<NormalArea>();
slash.Initialize<NormalArea>(this, Fraction.Player)
.SetAttackSubmodule<NormalArea>(attackUnit)
.SetTimeSubmodule<NormalArea>(5f)
.SetHitSubmodule<NormalArea>();
slash.SetImpulseSubmodule();
if (force == default)
{
slash.impulseSm.WithRepulsion(8f);
}
else
{
slash.impulseSm.WithCustomForce(force.normalized * 8f);
}
slash.topParent.position += positionOffset;
AudioManager.Post(AK.EVENTS.C1_AXE_SMASH, slash.gameObject);
return slash;
}
private NormalArea GenerateWhirlWind(string vfxName, AttackUnit attackUnit, float duration)
{
NormalArea slash = vfxData.SpawnVFX(vfxName, this).GetComponentInChildren<NormalArea>();
slash.Initialize<NormalArea>(this, Fraction.Player)
.SetAttackSubmodule<NormalArea>(attackUnit)
.SetTimeSubmodule<NormalArea>(1.3f, 0.04f, 0.86f)
.SetHitSubmodule<NormalArea>(0.2f, 4);
slash.SetImpulseSubmodule().WithSuction(2);
slash.hitSm.AddHitSound(AK.EVENTS.C1_AXE_SWINGHIT);
var topParticle = slash.topParent.GetComponent<ParticleSystem>();
topParticle.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear);
foreach (ParticleSystem particle in slash.topParent.GetComponent<VFXObject>().particles)
{
var main = particle.main;
main.duration = duration;
}
topParticle.Play();
return slash;
}
private void GenerateMeteor(string vfxName, AttackUnit attackUnit, Vector3 targetPosition)
{
// 直接生成包含指示器与陨石的单个特效
NormalArea meteor = vfxData.SpawnVFX(vfxName, this, targetPosition, Quaternion.identity).GetComponentInChildren<NormalArea>();
meteor.Initialize<NormalArea>(this, Fraction.Player)
.SetAttackSubmodule<NormalArea>(attackUnit)
.SetTimeSubmodule<NormalArea>(2, 0.85f, enableAction: ()=>
{
AudioManager.Post(AK.EVENTS.NEXUSCRAB_CLAWSTABBLAST, meteor.gameObject);
feedbackSc.PlayFeedback("MeteorImpact");
})
.SetHitSubmodule<NormalArea>();
// 施加冲击力与 repulsion
meteor.SetImpulseSubmodule().WithRepulsion(8);
}
private NormalArea GenerateMovingSlash(string vfxName, AttackUnit attackUnit, Vector3 position,
Vector3 direction, float duration, float speed)
{
NormalArea slash = vfxData.SpawnVFX(vfxName, this, position, Quaternion.LookRotation(direction)).GetComponentInChildren<NormalArea>();
GameObject blockVFX = vfxData.Get(vfxName).hitVFX;
slash.Initialize<NormalArea>(this, Fraction.Player)
.SetAttackSubmodule<NormalArea>(attackUnit)
.SetTimeSubmodule<NormalArea>(duration, 0.2f, duration - 0.2f)
.SetLinearDirectionMoveModule<NormalArea>(direction, speed, 5f, true, true, false, 1f)
.SetHitSubmodule<NormalArea>(); // 默认设置0.5秒判定间隔或单次判定
slash.hitSm.AddHitSound(AK.EVENTS.C1_AXE_SWINGHIT);
slash.SetImpulseSubmodule().WithDynamicForce(3f);
slash.reactionSm.hasPerfectWindowTime = false;
slash.reactionSm.generalBlockAction = blocker =>
{
var blockTransform = VFXObject.Spawn(blockVFX, this, slash.topParent.transform).transform;
blockTransform.SetParent(null);
LeanPool.Despawn(slash.topParent.gameObject);
};
return slash;
}
}
}