Files
beyond/Assets/Scripts/Skills/TreeSpotController.cs

824 lines
30 KiB
C#

using Beyond;
using DG.Tweening;
using PixelCrushers.Wrappers;
using Sirenix.OdinInspector;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Serialization;
using UnityEngine.UI;
namespace Beyond
{
public enum TreeState
{
Empty,
FreshlySeeded,
SmallTree,
MediumTree,
FullyGrown,
Sick
}
public enum TreeType //may not be needed, the fruit is being added from b trigger generic action
{
Apple,
Orange,
Banana
}
[System.Serializable]
public class TreeStateData
{
public TreeState treeState;
public float health = 100;
public bool isEnabled = true;
public TreeStateData(TreeState treeState, float health, bool isEnabled)
{
this.treeState = treeState;
this.health = health;
this.isEnabled = isEnabled;
}
}
[System.Serializable]
public class TreeSpotController : MonoBehaviour
{
public float health = 100, maxHealth = 100, fruitSicknessThreshold = 90;
public TreeState currentTreeState;
private float effectDelay = 0.80f;
public List<GameObject> fruits;
[Tooltip("double growth, so less steps are required ")]
[SerializeField] private bool doubleGrowthStep = true;
[SerializeField] private SphereCollider validatorCollider;
[SerializeField] private TriggerEvent validatorEventReceiver;
[SerializeField] private SphereCollider plantingCollider, fastGrowingCollider, healingCollider;
[SerializeField] private bTriggerGenericAction fastGrowingTrigger, healingTrigger;
[SerializeField] private GameObject infoTextObject;
[SerializeField] private Text infoText;
[SerializeField] private Animator treeAnimator;
[SerializeField] private AnimationCurve speedCurve;
[SerializeField] private AudioSource growAudio, healAudio;
private Color targetColor = Color.black, targetColorLeaves = new Color(1, 1, 1, 0);
private Color initialColor = Color.white;
private float bPGainOnAction = 1f;
[SerializeField] private List<Renderer> woodRenderers, leavesRenderers;
private List<Material> woodMaterials = new(), leavesMaterials = new();
private string woodColorName = "_BaseColor",
leavesColorName = "_BaseColor";
[SerializeField] public bItemListData items;
[FormerlySerializedAs("SetEmptyStateOnAwake")]
[SerializeField]
private bool setEmptyStateOnEnable = true;
[Header("")] [SerializeField] private Skills skillRequiredToPlant;
[HideInInspector] public bItem itemRequiredToPlant, itemRequiredToGrow, itemRequiredToHeal;
private const string growinAnimation = "Growing", fruitsAnimation = "Fruits ", sickAnimation = "Sick";
private const float freshlySeededSize = 0.3f,
smallTreeSize = 0.55f,
mediumTreeSize = 0.8f,
fullyGrownSize = 1f,
sickTree = 1f;
[Header("Events")] public UnityEvent onHealTree;
[Header("Events")] public UnityEvent<TreeState> onStateChanged;
[Header("Events")] public UnityEvent onFullyGrown;
private bool canPlayCantDoClip = true;
private void Awake()
{
StartCoroutine(AddOnInventoryUpdateEventCoroutine());
woodRenderers.ForEach(renderer => woodMaterials.Add(renderer.material));
leavesRenderers.ForEach(renderer => leavesMaterials.Add(renderer.material));
}
private void OnEnable()
{
if (setEmptyStateOnEnable)
{
ResetTreeInstant();
}
else
{
SetTreeStateInstant(currentTreeState);
}
canPlayCantDoClip = true;
}
private IEnumerator AddOnInventoryUpdateEventCoroutine()
{
yield return new WaitForEndOfFrame();
Player.Instance.ItemManager.onFinishItemDestroy += UpdateInteractionsOnInventoryUpdate;
UpdateInteractionsOnInventoryUpdate();
}
public void UpdateInteractionsOnInventoryUpdate()
{
if (currentTreeState == TreeState.Empty || currentTreeState == TreeState.FullyGrown)
{
return;
}
bItemManager itemManager = Player.Instance.ItemManager;
if (!itemManager.ContainItem(itemRequiredToGrow.id))
{
fastGrowingCollider.enabled = false;
// ResetInteractionButtonImage();
if (currentTreeState == TreeState.FreshlySeeded || currentTreeState == TreeState.SmallTree ||
currentTreeState == TreeState.MediumTree)
{
ActivateGrowSpeedUpValidator();
}
else if (currentTreeState == TreeState.Sick)
{
ActivateHealingValidator();
}
}
}
public void ResetTreeInstant()
{
SetTreeStateInstant(TreeState.Empty);
}
public void SetTreeStateInstant(TreeState treeState)
{
SetTreeState(treeState, true);
}
public void SetTreeState(TreeState treeState, bool instant)
{
DisableAllColliders();
StopAllCoroutines();
float animationValue = 0;
string animationName = "";
int animLayer = 0;
//empty-can plant
//freshly-medium can
switch (treeState)
{
case TreeState.Empty:
ActivatePlantingValidator();
break;
case TreeState.FreshlySeeded:
animationValue = freshlySeededSize;
animationName = growinAnimation;
ActivateGrowSpeedUpValidator();
break;
case TreeState.SmallTree:
animationValue = smallTreeSize;
animationName = growinAnimation;
ActivateGrowSpeedUpValidator();
break;
case TreeState.MediumTree:
animationValue = mediumTreeSize;
animationName = growinAnimation;
ActivateGrowSpeedUpValidator();
break;
case TreeState.FullyGrown: //no interaction available
//assume 90hp or less = fruits growing backwards
// 80-0 plaY sick animation
// health = 100;
//normally growing tree here
if (currentTreeState == TreeState.Sick)
{
animationValue = 0; //reverse sick animation
animationName = sickAnimation;
animLayer = 0;
LightenTreeColor();
}
else
{
animationValue = fullyGrownSize;
animationName = growinAnimation;
leavesMaterials.ForEach(material => material.DOColor(initialColor, leavesColorName, 1f));
}
//Player.Instance.PlayerInput.ChangeCameraStateWithLerp("Default");
StartCoroutine(ShowFruitsCoroutine());
//animLayer = 0;
break;
case TreeState.Sick:
animationValue = (maxHealth - health) / maxHealth;
animationName = sickAnimation;
animLayer = 0;
if (fruits[0].transform.localScale.x > 0)
{
StartCoroutine(HideFruitsCoroutine());
}
if (woodMaterials[0].GetColor(woodColorName).a > 0)
{
DarkenTreeColor();
}
ActivateHealingValidator();
//enable healing
break;
default:
break;
}
if (IsSettingValidForGrowAudio(treeState))
{
growAudio.Play();
}
currentTreeState = treeState;
//TODO make sure that is enough to deal with saved state and disabled trees
if (gameObject.activeInHierarchy)
{
if (instant)
{
StartCoroutine(SetInstantTreeSizeCoroutine(animationValue, animationName, animLayer));
}
else
{
StartCoroutine(SetAnimationTreeCoroutine(animationValue, animationName, animLayer));
}
}
onStateChanged?.Invoke(currentTreeState);
if (currentTreeState == TreeState.FullyGrown)
{
onFullyGrown?.Invoke();
}
}
private bool IsSettingValidForGrowAudio(TreeState treeState)
{
return treeState != TreeState.Empty && treeState != TreeState.Sick && currentTreeState != TreeState.Sick && growAudio;
}
private void DarkenTreeColor()
{
woodMaterials.ForEach(material => material.DOColor(targetColor, woodColorName, 1f));
leavesMaterials.ForEach(material => material.DOColor(targetColorLeaves, leavesColorName, 1f));
}
private void LightenTreeColor()
{
woodMaterials.ForEach(material => material.DOColor(initialColor, woodColorName, 1f));
leavesMaterials.ForEach(material => material.DOColor(initialColor, leavesColorName, 1f));
}
private IEnumerator ShowFruitsCoroutine()
{
yield return new WaitForSeconds(effectDelay);
float currentSize = 0;
float desiredSize = 1;
Vector3 scale = Vector3.zero;
while (currentSize < desiredSize)
{
currentSize += Time.deltaTime;
scale = new Vector3(currentSize, currentSize, currentSize);
fruits.ForEach(fruit => fruit.transform.localScale = scale);
yield return null;
}
}
private IEnumerator HideFruitsCoroutine()
{
float currentSize = 1;
float desiredSize = 0;
Vector3 scale = Vector3.zero;
while (currentSize > desiredSize)
{
currentSize -= Time.deltaTime;
scale = new Vector3(currentSize, currentSize, currentSize);
fruits.ForEach(fruit => fruit.transform.localScale = scale);
yield return null;
}
}
private void DisableAllColliders()
{
validatorCollider.enabled = false;
plantingCollider.enabled = false;
//ResetInteractionButtonImage();
fastGrowingCollider.enabled = false;
healingCollider.enabled = false;
}
private void ActivatePlantingValidator()
{
EnablePlantingValidatorCollider();
validatorEventReceiver.onTriggerEnter.RemoveAllListeners();
validatorEventReceiver.onTriggerEnter.AddListener(ValidateRequiredItemsToPlant);
validatorEventReceiver.onTriggerExit.RemoveAllListeners();
validatorEventReceiver.onTriggerExit.AddListener(EnablePlantingValidatorCollider);
}
public void EnablePlantingValidatorCollider(GameObject gameObject = null)
{
EnablePlantingValidatorCollider();
}
public void EnablePlantingValidatorCollider()
{
infoTextObject.SetActive(false);
validatorCollider.enabled = true;
plantingCollider.enabled = false;
}
private void ActivateGrowSpeedUpValidator()
{
EnableGrowSpeedValidatorCollider();
validatorEventReceiver.onTriggerEnter.RemoveAllListeners();
validatorEventReceiver.onTriggerEnter.AddListener(
ValidateRequiredItemToSpeedGrow); //validate different thing
validatorEventReceiver.onTriggerExit.RemoveAllListeners();
validatorEventReceiver.onTriggerExit.AddListener(EnableGrowSpeedValidatorCollider);
}
public void EnableGrowSpeedValidatorCollider(GameObject gameObject = null)
{
EnableGrowSpeedValidatorCollider();
}
public void EnableGrowSpeedValidatorCollider()
{
// infoTextObject.SetActive(false);
// fastGrowingCollider.enabled = false;
// validatorCollider.enabled = true;
StartCoroutine(EnableGrowingValidatorColliderCoroutine());
}
private IEnumerator EnableGrowingValidatorColliderCoroutine()
{
validatorCollider.enabled = false;
yield return new WaitForEndOfFrame();
infoTextObject.SetActive(false);
fastGrowingCollider.enabled = false;
validatorCollider.enabled = true;
// EnableGrowSpeedValidatorCollider();
}
private void ActivateHealingValidator()
{
DisableAllColliders();
StartCoroutine(EnableHealingColliderCoroutine());
validatorEventReceiver.onTriggerEnter.RemoveAllListeners();
validatorEventReceiver.onTriggerExit.RemoveAllListeners();
validatorEventReceiver.onTriggerEnter.AddListener(ValidateHealingRequirements);
validatorEventReceiver.onTriggerExit.AddListener(EnableHealingValidatorCollider);
}
public void EnableHealingValidatorCollider(GameObject gameObject = null)
{
EnableHealingValidatorCollider();
}
public void EnableHealingValidatorCollider()
{
StartCoroutine(EnableHealingValidatorColliderCoroutine());
}
private IEnumerator EnableHealingValidatorColliderCoroutine()
{
healingCollider.enabled = false;
validatorCollider.enabled = false;
infoTextObject.SetActive(false);
yield return new WaitForSeconds(0.6f);
validatorCollider.enabled = true;
healingCollider.enabled = false;
}
public void ValidateRequiredItemsToPlant(GameObject gameObject = null)
{
if (currentTreeState != TreeState.Empty)
{
infoTextObject.SetActive(false);
// ResetInteractionButtonImage();
validatorCollider.enabled = false;
plantingCollider.enabled = false;
return;
}
infoTextObject.SetActive(true);
if (SkillsManager.instance.GetSkillLevelOf(skillRequiredToPlant) > 0)
{
bItemManager itemManager = Player.Instance.ItemManager;
if (itemManager.ContainItem(itemRequiredToPlant.id))
{
validatorCollider.enabled = false;
infoText.text = "Plant seed";
plantingCollider.enabled = true;
}
else
{
plantingCollider.enabled = false;
infoTextObject.SetActive(true);
infoText.text = "Requires " + itemRequiredToPlant.name;
}
}
else
{
infoTextObject.SetActive(true);
infoText.text = "Requires " + SkillsManager.instance.GetStringNameOf(skillRequiredToPlant);
}
}
public void ValidateRequiredItemToSpeedGrow(GameObject gameObject = null)
{
if (currentTreeState == TreeState.FullyGrown)
{
ResetInteractionButtonImage();
infoTextObject.SetActive(false);
validatorCollider.enabled = false;
fastGrowingCollider.enabled = false;
return;
}
infoTextObject.SetActive(true);
int level = SkillsManager.instance.GetSkillLevelOf(Skills.MasterOfScrolls);
if (level <= 0)
{
infoText.text = "Requires " + SkillsManager.instance.GetStringNameOf(Skills.MasterOfScrolls);
return;
}
bItemManager itemManager = Player.Instance.ItemManager;
if (itemManager.ContainItem(itemRequiredToGrow.id))
{
validatorCollider.enabled = false;
infoText.text = "Accelerated growth";
fastGrowingCollider.enabled = true;
// StartCoroutine(EnableFastGrowingColliderCoroutine());
}
else
{
ResetInteractionButtonImage();
fastGrowingCollider.enabled = false;
validatorCollider.enabled = true;
infoTextObject.SetActive(true);
infoText.text = "Requires " + itemRequiredToGrow.name;
}
}
private IEnumerator EnableFastGrowingColliderCoroutine()
{
fastGrowingCollider.enabled = false;
yield return new WaitForSeconds(0.95f);
validatorCollider.enabled = false;
infoText.text = "Accelerated growth";
fastGrowingCollider.enabled = true;
}
public void ValidateHealingRequirements(GameObject gameObject = null)
{
if (currentTreeState != TreeState.Sick)
{
infoTextObject.SetActive(false);
ResetInteractionButtonImage();
validatorCollider.enabled = false;
fastGrowingCollider.enabled = false;
return;
}
infoTextObject.SetActive(true);
int level = SkillsManager.instance.GetSkillLevelOf(Skills.MasterOfScrolls);
if (level <= 0)
{
infoText.text = "Requires " + SkillsManager.instance.GetStringNameOf(Skills.MasterOfScrolls);
return;
}
bItemManager itemManager = Player.Instance.ItemManager;
if (itemManager.ContainItem(itemRequiredToHeal.id))
{
validatorCollider.enabled = false;
infoText.text = "Heal tree";
healingCollider.enabled = true;
}
else
{
infoText.text = "Requires " + itemRequiredToHeal.name;
}
}
private IEnumerator EnableHealingColliderCoroutine()
{
validatorCollider.enabled = false;
yield return new WaitForEndOfFrame();
yield return new WaitForEndOfFrame();
yield return new WaitForSeconds(0.3f);
validatorCollider.enabled = true;
}
public void DisableValidationTexts(GameObject gameObject = null)
{
//useless
infoTextObject.SetActive(false);
}
public void SetPlantInteractionButtonImage()
{
Player.Instance.SetInteractableButtonImage(Resources.Load<Sprite>(itemRequiredToPlant.secondaryIconPath));
}
public void SetFastGrowInteractionButtonImage()
{
Player.Instance.SetInteractableButtonImage(Resources.Load<Sprite>(itemRequiredToGrow.iconPath));
}
public void ResetInteractionButtonImage()
{
Player.Instance.ResetIntaractableButtonImage();
}
private IEnumerator SetInstantTreeSizeCoroutine(float size, string animationName, int layer = 0)
{
treeAnimator.enabled = true;
treeAnimator.Play(animationName, layer, size);
yield return
new WaitUntil(() =>
treeAnimator.GetCurrentAnimatorStateInfo(0).IsName(animationName)); //could use while with no gc
yield return new WaitUntil(() => treeAnimator.GetCurrentAnimatorStateInfo(0).normalizedTime >= size);
treeAnimator.enabled = false;
}
private IEnumerator SetAnimationTreeCoroutine(float size, string animationName, int layer = 0)
{
treeAnimator.enabled = true;
treeAnimator.Play(animationName, layer);
yield return new WaitUntil(() => treeAnimator.GetCurrentAnimatorStateInfo(0).IsName(animationName));
float startingSize = treeAnimator.GetCurrentAnimatorStateInfo(0).normalizedTime;
if (size < startingSize)
{
treeAnimator.SetFloat("speedMultiplier", -1); // = -1;
while (treeAnimator.GetCurrentAnimatorStateInfo(0).normalizedTime > size)
{
yield return null;
treeAnimator.speed =
speedCurve.Evaluate(
(-treeAnimator.GetCurrentAnimatorStateInfo(0).normalizedTime + startingSize) /
(-size + startingSize));
}
}
else
{
treeAnimator.SetFloat("speedMultiplier", 1); // = -1;
while (treeAnimator.GetCurrentAnimatorStateInfo(0).normalizedTime <= size)
{
yield return null;
treeAnimator.speed =
speedCurve.Evaluate(
(treeAnimator.GetCurrentAnimatorStateInfo(0).normalizedTime - startingSize) /
(size - startingSize));
}
}
Player.Instance.PlayerInput.ChangeCameraStateWithLerp("Default");
treeAnimator.enabled = false;
}
/// <summary>
/// spammming in editor will break animator
/// </summary>
public void GrowTree()
{
Player.Instance.PlayerInput.ChangeCameraStateWithLerp("Tree");
switch (currentTreeState)
{
case TreeState.Empty:
if (!doubleGrowthStep)
SetTreeStateAnimated(TreeState.FreshlySeeded);
else
SetTreeStateAnimated(TreeState.SmallTree);
break;
case TreeState.FreshlySeeded:
if (!doubleGrowthStep)
SetTreeStateAnimated(TreeState.SmallTree);
else
SetTreeStateAnimated(TreeState.MediumTree);
break;
case TreeState.SmallTree:
if (!doubleGrowthStep)
SetTreeStateAnimated(TreeState.MediumTree);
else
SetTreeStateAnimated(TreeState.FullyGrown);
break;
case TreeState.MediumTree:
SetTreeStateAnimated(TreeState.FullyGrown);
break;
case TreeState.FullyGrown:
break;
default:
break;
}
}
public void SetTreeStateAnimated(TreeState plantState)
{
SetTreeState(plantState, false);
}
public void PlantTree()
{
bItemManager itemManager = Player.Instance.ItemManager;
bItem itemToDestroy = itemManager.GetItem(itemRequiredToPlant.id);
itemManager.UseItem(itemToDestroy);
Player.Instance.SetBrightness(Player.Instance.GetBrightness() + bPGainOnAction);
//GrowTree();
StartCoroutine(PlantTreeCoroutine());
}
private IEnumerator PlantTreeCoroutine()
{
yield return new WaitForSeconds(effectDelay);
// fastGrowingTrigger.OnInvalidate?.Invoke(gameObject);
GrowTree();
}
public void TryToGrowTree()
{
PlayerAttribute faithAttribute = Player.Instance.GetAttribute("Faith");
bItemAttribute itemFaithCost = itemRequiredToGrow.GetItemAttribute(bItemAttributes.Faith);
//EnableGrowSpeedValidatorCollider();
if (itemFaithCost.value > faithAttribute.AttributeCurrentValue)
{
TryToPlayNotEnoughFaithClip();
fastGrowingTrigger.playAnimation = "";
return;
}
//fastGrowingTrigger.playAnimation = "Pick_Up";
fastGrowingTrigger.playAnimation = "Grow Tree";
// fastGrowingTrigger.animatorLayer = 9;
faithAttribute.AttributeCurrentValue -= itemFaithCost.value;
bItemManager itemManager = Player.Instance.ItemManager;
bItem itemToDestroy = itemManager.GetItem(itemRequiredToGrow.id);
itemManager.UseItem(itemToDestroy);
Player.Instance.SetBrightness(Player.Instance.GetBrightness() + bPGainOnAction);
// GrowTree();
StartCoroutine(GrowTreeCoroutine());
}
private IEnumerator GrowTreeCoroutine()
{
yield return new WaitForSeconds(effectDelay);
fastGrowingTrigger.OnInvalidate?.Invoke(gameObject);
GrowTree();
}
public void SetHealingInteractionButtonImage()
{
Player.Instance.SetInteractableButtonImage(Resources.Load<Sprite>(itemRequiredToHeal.iconPath));
}
public void DisableValidations(GameObject gameObject = null)
{
infoTextObject.SetActive(false);
DisableAllColliders();
}
public void DisableInfoText(GameObject gameObject = null)
{
infoTextObject.SetActive(false);
}
public void TryToHeal()
{
bItemAttribute itemFaithCost = itemRequiredToHeal.GetItemAttribute(bItemAttributes.Faith);
if (itemFaithCost.value > Player.Instance.GetCurrentFaithValue())
{
TryToPlayNotEnoughFaithClip();
// healingTrigger.OnInvalidate?.Invoke(gameObject);
healingTrigger.playAnimation = "";
// healingTrigger.endExitTimeAnimation = 0f;
// EnableHealingValidatorCollider();
return;
}
// healingTrigger.endExitTimeAnimation = 0.8f;
// healingTrigger.playAnimation = "Pick_Up";
healingTrigger.playAnimation = "Heal Tree";
// healingTrigger.OnInvalidate?.Invoke(gameObject);
Player.Instance.UpdateFaithCurrentValue(-itemFaithCost.value);
// faithAttribute.AttributeCurrentValue -= itemFaithCost.value;
bItemManager itemManager = Player.Instance.ItemManager;
bItem itemToDestroy = itemManager.GetItem(itemRequiredToHeal.id);
itemManager.UseItem(itemToDestroy);
Player.Instance.SetBrightness(Player.Instance.GetBrightness() + bPGainOnAction);
// SetTreeState(TreeState.FullyGrown, false);
//StartCoroutine(HealTreeCoroutine());
HealTree();
}
private void TryToPlayNotEnoughFaithClip()
{
if (!canPlayCantDoClip)
{
return;
}
canPlayCantDoClip = false;
DOVirtual.DelayedCall(1, () => canPlayCantDoClip = true);
var text = $"Not enough Faith";
bItemCollectionDisplay.Instance.FadeText(text, 4, 0.25f);
Player.Instance.PlayNoFaithClip();
}
private IEnumerator HealTreeCoroutine()
{
yield return new WaitForSeconds(effectDelay);
infoTextObject.SetActive(false);
if (healAudio)
{
healAudio.Play();
}
onHealTree?.Invoke();
SetTreeState(TreeState.FullyGrown, false);
}
public void HealTree()
{
health = 100;
healingCollider.enabled = false;
StartCoroutine(HealTreeCoroutine());
}
public void SickenTree(float sickValue)
{
health -= sickValue;
// SetTreeState(TreeState.Sick, false);
StartCoroutine(SickenTreeCoroutine());
}
private IEnumerator SickenTreeCoroutine()
{
yield return new WaitForSeconds(effectDelay);
SetTreeState(TreeState.Sick, false);
}
public void RotateGrowUpColliderForProperAnimation()
{
Vector3 heading = fastGrowingCollider.transform.position - Player.Instance.transform.position;
float distance = heading.magnitude;
Vector3 direction = heading / distance; // This is now the normalized direction.
fastGrowingCollider.transform.forward = direction;
}
public void RotatePlantingColliderForProperAnimation()
{
Vector3 heading = plantingCollider.transform.position - Player.Instance.transform.position;
float distance = heading.magnitude;
Vector3 direction = heading / distance; // This is now the normalized direction.
plantingCollider.transform.forward = direction;
}
public void RotateHealingColliderForProperAnimation()
{
Vector3 heading = healingCollider.transform.position - Player.Instance.transform.position;
float distance = heading.magnitude;
Vector3 direction = heading / distance; // This is now the normalized direction.
healingCollider.transform.forward = direction;
}
private void OnDestroy()
{
if (validatorEventReceiver)
{
validatorEventReceiver.onTriggerEnter.RemoveAllListeners();
validatorEventReceiver.onTriggerExit.RemoveAllListeners();
}
}
}
}