quantum-space-buddies/QSB/EchoesOfTheEye/Ghosts/Actions/QSBHuntAction.cs
2022-04-14 12:45:56 +01:00

300 lines
7.7 KiB
C#

using System;
using System.Collections.Generic;
using GhostEnums;
using QSB.EchoesOfTheEye.Ghosts;
using QSB.EchoesOfTheEye.Ghosts.WorldObjects;
using QSB.Utility;
using UnityEngine;
public class QSBHuntAction : QSBGhostAction
{
private int _numNodesToSearch;
private GhostNodeMap.NodeSearchData[] _nodesToSearch;
private int _currentNodeIndex;
private GhostNode _closestNode;
private bool _startAtClosestNode;
private bool _huntStarted;
private float _huntStartTime;
private bool _huntFailed;
private float _huntFailTime;
private List<int> _spotlightIndexList = new List<int>(16);
private int _spotlightIndex = -1;
public override void Initialize(QSBGhostBrain brain)
{
base.Initialize(brain);
_numNodesToSearch = 0;
_nodesToSearch = new GhostNodeMap.NodeSearchData[_controller.AttachedObject.GetNodeMap().GetNodeCount()];
_currentNodeIndex = 0;
_huntStarted = false;
_huntStartTime = 0f;
_huntFailed = false;
_huntFailTime = 0f;
_controller.AttachedObject.OnNodeMapChanged += new OWEvent.OWCallback(OnNodeMapChanged);
}
private void OnNodeMapChanged()
{
if (_running)
{
Debug.LogError("Changing node maps while the Hunt action is running is almost definitely not supported!");
_huntFailed = true;
}
_numNodesToSearch = 0;
_nodesToSearch = new GhostNodeMap.NodeSearchData[_controller.AttachedObject.GetNodeMap().GetNodeCount()];
_currentNodeIndex = 0;
}
public override GhostAction.Name GetName()
{
return GhostAction.Name.Hunt;
}
public override float CalculateUtility()
{
if (_data.interestedPlayer == null)
{
return -100f;
}
if (_data.threatAwareness < GhostData.ThreatAwareness.IntruderConfirmed)
{
return -100f;
}
if (_huntFailed && _huntFailTime > _data.interestedPlayer.timeLastSawPlayer)
{
return -100f;
}
if (_running || _data.interestedPlayer.timeSincePlayerLocationKnown < 60f)
{
return 80f;
}
return -100f;
}
protected override void OnEnterAction()
{
_controller.SetLanternConcealed(true, true);
_controller.FaceVelocity();
_effects.SetMovementStyle(GhostEffects.MovementStyle.Normal);
if (!_huntStarted || _data.interestedPlayer.timeLastSawPlayer > _huntStartTime)
{
var knownPlayerVelocity = _data.interestedPlayer.lastKnownSensor.knowsPlayerVelocity ? _data.interestedPlayer.lastKnownPlayerLocation.localVelocity : Vector3.zero;
_numNodesToSearch = _controller.AttachedObject.GetNodeMap().FindPossiblePlayerNodes(_data.interestedPlayer.lastKnownPlayerLocation.localPosition, knownPlayerVelocity, 30f, _nodesToSearch, true, null, null, null);
_currentNodeIndex = 0;
_startAtClosestNode = false;
_closestNode = null;
_huntStarted = true;
_huntStartTime = Time.time;
_huntFailed = false;
if (_numNodesToSearch == 0)
{
DebugLog.DebugWrite($"{_brain.AttachedObject._name} : Failed to find nodes to hunt player.", OWML.Common.MessageType.Error);
_huntFailed = true;
_huntFailTime = Time.time;
}
}
if (!_huntFailed)
{
_closestNode = _controller.AttachedObject.GetNodeMap().FindClosestNode(_controller.AttachedObject.GetLocalFeetPosition());
for (var i = 0; i < _closestNode.visibleNodes.Count; i++)
{
for (var j = 0; j < _numNodesToSearch; j++)
{
if (_closestNode.visibleNodes[i] == _nodesToSearch[j].node.index)
{
_startAtClosestNode = true;
break;
}
}
}
if (_startAtClosestNode)
{
_controller.PathfindToNode(_closestNode, MoveType.SEARCH);
}
else
{
_controller.PathfindToNode(_nodesToSearch[_currentNodeIndex].node, MoveType.SEARCH);
}
_effects.PlayVoiceAudioNear(AudioType.Ghost_Hunt, 1f);
}
}
protected override void OnExitAction()
{
if (_huntFailed && !_data.interestedPlayer.isPlayerLocationKnown)
{
DebugLog.DebugWrite($"{_brain.AttachedObject._name} : Hunt failed. :(");
_effects.PlayVoiceAudioNear(AudioType.Ghost_HuntFail, 1f);
}
}
public override bool Update_Action()
{
return !_huntFailed && !_data.interestedPlayer.isPlayerLocationKnown;
}
public override void FixedUpdate_Action()
{
if (_huntStarted && !_huntFailed && _spotlightIndexList.Count > 0 && !_controller.AttachedObject.GetDreamLanternController().IsConcealed())
{
for (var i = 0; i < _spotlightIndexList.Count; i++)
{
if (!_nodesToSearch[_spotlightIndexList[i]].searched)
{
var from = _nodesToSearch[_spotlightIndexList[i]].node.localPosition - _controller.AttachedObject.GetLocalFeetPosition();
var light = _controller.AttachedObject.GetDreamLanternController().GetLight();
var to = _controller.AttachedObject.WorldToLocalDirection(light.transform.forward);
if (Vector3.Angle(from, to) < (light.GetLight().spotAngle * 0.5f) - 5f && from.sqrMagnitude < light.range * light.range)
{
_nodesToSearch[_spotlightIndexList[i]].searched = true;
}
}
}
}
}
public override void OnTraversePathNode(GhostNode node)
{
for (var i = 0; i < _numNodesToSearch; i++)
{
if (node == _nodesToSearch[i].node)
{
_nodesToSearch[i].searched = true;
}
}
}
public override void OnArriveAtPosition()
{
GhostNode node;
if (_startAtClosestNode)
{
_startAtClosestNode = false;
node = _closestNode;
for (var i = 0; i < _numNodesToSearch; i++)
{
if (_closestNode == _nodesToSearch[i].node)
{
_nodesToSearch[i].searched = true;
break;
}
}
}
else
{
node = _nodesToSearch[_currentNodeIndex].node;
_nodesToSearch[_currentNodeIndex].searched = true;
}
GenerateSpotlightList(node);
if (_spotlightIndexList.Count > 0)
{
_controller.SetLanternConcealed(false, true);
SpotlightNextNode();
return;
}
TryContinueSearch();
}
public override void OnFaceNode(GhostNode node)
{
var num = _spotlightIndexList[_spotlightIndex];
if (node != _nodesToSearch[num].node)
{
Debug.LogError("Why are we facing this node??? " + node.name);
Debug.Break();
return;
}
_nodesToSearch[num].searched = true;
for (var i = _spotlightIndexList.Count - 1; i >= 0; i--)
{
if (_nodesToSearch[_spotlightIndexList[i]].searched)
{
_spotlightIndexList.RemoveAt(i);
}
}
if (_spotlightIndexList.Count > 0)
{
SpotlightNextNode();
return;
}
_controller.SetLanternConcealed(true, true);
_controller.FaceVelocity();
TryContinueSearch();
}
private void SpotlightNextNode()
{
_spotlightIndex = 0;
var num = _spotlightIndexList[_spotlightIndex];
_controller.FaceNode(_nodesToSearch[num].node, TurnSpeed.MEDIUM, 1f, true);
}
private void TryContinueSearch()
{
if (Time.time > _enterTime + 60f)
{
_huntFailed = true;
_huntFailTime = Time.time;
return;
}
while (_nodesToSearch[_currentNodeIndex].searched && _currentNodeIndex < _numNodesToSearch)
{
_currentNodeIndex++;
}
if (_currentNodeIndex < _numNodesToSearch)
{
DebugLog.DebugWrite($"{_brain.AttachedObject._name} : Moving to hunt at new node.");
_controller.PathfindToNode(_nodesToSearch[_currentNodeIndex].node, MoveType.SEARCH);
return;
}
_huntFailed = true;
_huntFailTime = Time.time;
}
private void GenerateSpotlightList(GhostNode node)
{
_spotlightIndexList.Clear();
for (var i = 0; i < node.visibleNodes.Count; i++)
{
for (var j = 0; j < _numNodesToSearch; j++)
{
if (!_nodesToSearch[j].searched && node.visibleNodes[i] == _nodesToSearch[j].node.index)
{
_spotlightIndexList.Add(j);
}
}
}
}
public override void DrawGizmos(bool isGhostSelected)
{
if (isGhostSelected)
{
for (var i = 0; i < _numNodesToSearch; i++)
{
var t = Mathf.Abs(_nodesToSearch[i].score) / 180f;
Popcron.Gizmos.Sphere(
_controller.AttachedObject.LocalToWorldPosition(_nodesToSearch[i].node.localPosition),
(i < _currentNodeIndex) ? 0.5f : 2f,
_nodesToSearch[i].searched ? Color.black : Color.HSVToRGB(Mathf.Lerp(0.5f, 0f, t), 1f, 1f));
}
}
}
}