134 lines
4.3 KiB
C#
134 lines
4.3 KiB
C#
using Cielonos.MainGame.Characters.AI;
|
|
using Opsive.BehaviorDesigner.Runtime.Tasks;
|
|
using Opsive.Shared.Utility;
|
|
using UnityEngine;
|
|
|
|
namespace Cielonos.MainGame.Characters.AI
|
|
{
|
|
[Category("Cielonos/Rhythm")]
|
|
[Description("Returns Success if an upcoming beat containing a tag that starts with 'EnemyAttack' is within the lead time. Otherwise returns Failure.")]
|
|
public class RhythmAttackDetector : AutomataConditionalBase
|
|
{
|
|
[Tooltip("The lead time before the beat in seconds.")]
|
|
public float leadTime = 0.1f;
|
|
|
|
[Tooltip("The prefix of the tag to match.")]
|
|
public string tagPrefix = "EnemyAttack";
|
|
|
|
private MusicBeatSystem _beatSystem;
|
|
private ILocalRhythmTracker _localTracker;
|
|
private BeatMarker _lastTriggeredBeat;
|
|
|
|
public override void OnAwake()
|
|
{
|
|
base.OnAwake();
|
|
_beatSystem = CombatManager.GetCombatSystem<MusicBeatSystem>();
|
|
_localTracker = gameObject.GetComponent<ILocalRhythmTracker>();
|
|
}
|
|
|
|
public override void OnStart()
|
|
{
|
|
_lastTriggeredBeat = null;
|
|
}
|
|
|
|
public override TaskStatus OnUpdate()
|
|
{
|
|
MusicBeatData activeData = null;
|
|
float currentSongTime = 0f;
|
|
bool isActive = false;
|
|
|
|
if (_localTracker != null && _localTracker.CurrentBeatData != null)
|
|
{
|
|
activeData = _localTracker.CurrentBeatData;
|
|
currentSongTime = _localTracker.CurrentSongTime;
|
|
isActive = _localTracker.IsPlaying;
|
|
}
|
|
else if (_beatSystem != null && _beatSystem.IsActive && _beatSystem.CurrentBeatData != null)
|
|
{
|
|
activeData = _beatSystem.CurrentBeatData;
|
|
currentSongTime = _beatSystem.CurrentSongTime;
|
|
isActive = _beatSystem.IsPlaying;
|
|
}
|
|
|
|
if (!isActive || activeData == null)
|
|
{
|
|
return TaskStatus.Failure;
|
|
}
|
|
|
|
BeatMarker targetBeat = FindNextMatchingBeat(activeData, currentSongTime);
|
|
if (targetBeat == null)
|
|
{
|
|
return TaskStatus.Failure;
|
|
}
|
|
|
|
// If we have already triggered for this specific beat, we shouldn't succeed again
|
|
if (_lastTriggeredBeat == targetBeat)
|
|
{
|
|
return TaskStatus.Failure;
|
|
}
|
|
|
|
float timeUntilBeat = targetBeat.time - currentSongTime;
|
|
|
|
// Check if we are within the lead time window
|
|
if (timeUntilBeat <= leadTime)
|
|
{
|
|
TriggerDetection(targetBeat, timeUntilBeat);
|
|
return TaskStatus.Success;
|
|
}
|
|
|
|
return TaskStatus.Failure;
|
|
}
|
|
|
|
private BeatMarker FindNextMatchingBeat(MusicBeatData activeData, float currentTime)
|
|
{
|
|
var markers = activeData.beatMarkers;
|
|
|
|
if (markers == null) return null;
|
|
|
|
for (int i = 0; i < markers.Count; i++)
|
|
{
|
|
BeatMarker marker = markers[i];
|
|
|
|
// Check for upcoming beats
|
|
if (marker.time > currentTime)
|
|
{
|
|
if (marker.tags != null)
|
|
{
|
|
for (int j = 0; j < marker.tags.Count; j++)
|
|
{
|
|
if (marker.tags[j].StartsWith(tagPrefix))
|
|
{
|
|
return marker;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private void TriggerDetection(BeatMarker beat, float timeUntilBeat)
|
|
{
|
|
_lastTriggeredBeat = beat;
|
|
|
|
// Log matching tags for identification
|
|
string matchedTag = "";
|
|
if (beat.tags != null)
|
|
{
|
|
foreach (string t in beat.tags)
|
|
{
|
|
if (t.StartsWith(tagPrefix))
|
|
{
|
|
matchedTag = t;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Debug.Log($"[RhythmAttackDetector] Conditional MET for {self.gameObject.name} at {beat.time:F3}s " +
|
|
$"(in {timeUntilBeat:F3}s) with matched tag '{matchedTag}'.");
|
|
}
|
|
}
|
|
}
|