using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NewCharacterScript : MonoBehaviour
{
public GameObject orbitCenter;
public ParticleSystem deathAnimator;
public SpriteRenderer spriteHolder;
public AudioClip[] deathSounds;
public AudioClip[] takingSounds;
public AudioClip[] hitSounds;
public AudioClip[] dragInHoleSounds;
public ParticleSystem leaderLightSystem;
public ParticleSystem lightSystem;
public UnitUIModel uiModel;
private ParticleSystem.MainModule lightSystemMain;
private ParticleSystem.MainModule leaderLightSystemMain;
[SerializeField]
private Animator spriteAnimator;
private List<SpellModel> timedSpells = new List<SpellModel>();
private float shortestTimeSpell = float.MaxValue;
public float minScale = 0.5f;
public float maxScale = 1.2f;
protected float maxRadiusOffset = 3f;
protected float radiusOffsetFactor = 20f;
protected float speed = 6f;
protected Vector3 targetPosition;
protected Vector3 targetTranslate;
public bool isDefence = true;
public bool isDead = false;
private bool isPaused = false;
public string characterName = "";
public NewCharacterScript killer;
public string killerName = "";
public Color color = Color.white;
public Color unitColor;
protected bool isForceUndefence = false;
private AudioSource audioSource;
private float haste = 0f;
private float hasteDuration = 0f;
protected const float selfRotatingSpeed = 120f;
private float timerResurrectLayer = 3;
private bool isTimerEnabled = false;
protected float spriteAngle = 0;
protected GameHandlerScript gameHandler;
[SerializeField] protected Renderer unitRenderer;
protected List<GameObject> victims = new List<GameObject>();
protected float bonusPercentSpeed = 1f;
public List<NewRazerScript> weaponCollection = new List<NewRazerScript>();
public bool ThinkToResurrect
{
get;
protected set;
}
private const float scaleFactor = 0.01f;
// SpellsBonuses
protected float bonusHasteDuration = 0f;
protected float deflectionBonus = 0f;
protected float attackRadiusBonus = 0f;
protected float blockRadiusBonus = 0f;
//void OnTriggerStay2D(Collider2D collision)
//{
// HandleCollision(collision.gameObject);
//}
private void Awake()
{
SharedProperties.handlerGamePause += OnPauseEnabled;
}
private void OnDestroy()
{
ResurrectView.ResurrectAcceptEvent -= OnResurrectAccept;
SharedProperties.handlerGamePause -= OnPauseEnabled;
}
public virtual void OnTriggerEnter2D(Collider2D collision)
{
if (ThinkToResurrect) return;
if (collision.gameObject.tag == "obstacleKiller")
{
killerName = "Accient";
HandleDeath();
}
else if (collision.gameObject.tag == "weapon" && !isDead)
{
if (collision.gameObject.GetComponent<NewRazerScript>().state == RazerState.InActive)
{
collision.gameObject.GetComponent<CapsuleCollider2D>().isTrigger = false;
}
}
else if (collision.gameObject.tag == "bonus" && !isDead)
{
var bonusScript = collision.gameObject.GetComponent<HasteScript>();
if (bonusScript != null)
{
GetHaste(bonusScript);
}
}
}
public virtual void OnCollisionStay2D(Collision2D collision)
{
if (ThinkToResurrect) return;
HandleCollision(collision.gameObject);
}
public virtual void Start()
{
if (spriteAnimator != null) spriteAnimator.StopPlayback();
deathAnimator.Stop();
leaderLightSystem.Stop();
leaderLightSystemMain = leaderLightSystem.main;
lightSystemMain = lightSystem.main;
audioSource = GetComponent<AudioSource>();
audioSource.dopplerLevel = 0;
targetPosition = transform.position;
targetTranslate = Vector3.zero;
gameHandler = GameHandlerScript.Instance;
ApplySpells();
}
public virtual void Update()
{
if (isPaused || ThinkToResurrect) return;
if(spriteAnimator != null) spriteAnimator.SetBool("isInvulnerable", IsInvulnerable());
if(timedSpells.Count > 0 && shortestTimeSpell < Time.time)
{
UpdateTimedSpells();
}
if (hasteDuration > 0)
{
hasteDuration -= Time.deltaTime;
}
else
{
haste = 0f;
}
if (isTimerEnabled == true)
{
timerResurrectLayer -= Time.deltaTime;
ChangeLayer("ResurrectLayer");
if (timerResurrectLayer < 0)
{
isTimerEnabled = false;
ChangeLayer("UnitLayer");
}
}
}
public virtual void FixedUpdate()
{
if (isDead || isPaused || ThinkToResurrect)
return;
if (gameHandler.isMenu)
{
if (Input.touchCount != 0)
{
weaponCollection.ForEach(PerformAttack);
}
else
{
Defence();
}
}
else
{
if (targetTranslate != Vector3.zero || Vector3.Distance(transform.position, targetPosition) > 0.01f || isForceUndefence)
{
MoveToTargetPosition(Time.deltaTime);
}
else
{
Defence();
}
}
}
protected virtual void OnPauseEnabled(bool value)
{
isPaused = value;
//player.GetComponent<Renderer>().enabled = !value;
}
public void SetName(string name)
{
this.characterName = name;
}
protected virtual void MoveToTargetPosition(float deltaTime)
{
if (isDead) return;
if (!gameHandler.GetAvaliableBounds().Contains(targetPosition))
{
targetPosition = transform.position;
}
var step = (speed * bonusPercentSpeed + haste) * deltaTime;
weaponCollection.ForEach(PerformAttack);
float playerOffset = 0.3f;
Bounds mapBounds = gameHandler.GetMapBounds();
if (targetPosition.x - playerOffset < mapBounds.min.x)
{
targetPosition.x = mapBounds.min.x + playerOffset;
}
if (targetPosition.y - playerOffset < mapBounds.min.y)
{
targetPosition.y = mapBounds.min.y + playerOffset;
}
if (targetPosition.x + playerOffset > mapBounds.max.x)
{
targetPosition.x = mapBounds.max.x - playerOffset;
}
if (targetPosition.y + playerOffset > mapBounds.max.y)
{
targetPosition.y = mapBounds.max.y - playerOffset;
}
if (!targetPosition.Equals(transform.position))
{
spriteAngle = Mathf.Atan2(transform.position.y - targetPosition.y, transform.position.x - targetPosition.x) * Mathf.Rad2Deg + 90;
spriteAngle = spriteAngle > 180f ? spriteAngle - 360f : spriteAngle;
spriteAngle = spriteAngle < -180f ? spriteAngle + 360f : spriteAngle;
if (spriteAngle > 90f)
{
spriteAngle = 30f;
}
else if (spriteAngle > 0f)
{
spriteAngle = -30f;
}
else if (spriteAngle < -90f)
{
spriteAngle = -30f;
}
else if (spriteAngle < 0f)
{
spriteAngle = 30f;
}
}
else
{
spriteAngle = 0f;
}
transform.position = Vector2.MoveTowards(transform.position, targetPosition, step);
}
protected virtual void Defence()
{
spriteAngle = 0f;
weaponCollection.ForEach(PerformDefence);
}
public virtual void AppendWeapon(NewRazerScript objectScript)
{
PlayRazerTakingSound();
weaponCollection.Add(objectScript);
objectScript.transform.SetParent(orbitCenter.transform);
objectScript.owner = this;
objectScript.orbitCenter = orbitCenter;
objectScript.PerformCommand(RazerCommand.GoToOwner);
objectScript.SetUnitUIModel(uiModel);
RecalculateAngles();
}
public float GetRadius()
{
var weaponCount = GetWeaponsCount();
var offset = weaponCount / radiusOffsetFactor;
offset = offset > maxRadiusOffset ? maxRadiusOffset : offset;
float width = unitRenderer.bounds.size.x;
float radius = width * 3.5f;
float targetRadius = radius + offset;
float bonusRadius = 0f;
if (isDefence)
{
bonusRadius = targetRadius * blockRadiusBonus;
}
else
{
bonusRadius = targetRadius * attackRadiusBonus;
}
targetRadius += bonusRadius;
return targetRadius;
}
public virtual void RecalculateAngles()
{
var weaponsCount = weaponCollection.Count;
// Light systems
var newScale = Mathf.Min(weaponsCount / 10f, 1.5f);
lightSystem.transform.localScale = new Vector2(newScale, newScale);
leaderLightSystem.transform.localScale = new Vector2(newScale, newScale);
// Weapons
if (weaponsCount == 0) return;
float angleOffset = Mathf.Deg2Rad * 360f / weaponsCount;
float startAngle = weaponCollection[0].GetTargetAngle();
for (int i = 0; i < weaponsCount; i++)
{
NewRazerScript razerScript = weaponCollection[i];
float targetAngle = Mathf.Repeat(startAngle + (i * angleOffset), Mathf.Deg2Rad * 360f);
razerScript.SetTargetAngle(targetAngle);
}
}
void PerformAttack(NewRazerScript obj)
{
obj.PerformCommand(RazerCommand.Attack);
}
void PerformDefence(NewRazerScript obj)
{
obj.PerformCommand(RazerCommand.Defence);
}
public virtual void ZoomOutCamera()
{
float scale = transform.localScale.x;
if (scale >= maxScale)
{
return;
}
float newScale = scale + scaleFactor;
newScale = newScale > maxScale ? maxScale : newScale;
Vector3 newScaleVector = new Vector3(newScale, newScale, newScale);
transform.localScale = newScaleVector;
}
public virtual void ZoomInCamera()
{
float scale = transform.localScale.x;
if (scale <= minScale)
{
return;
}
float newScale = scale - scaleFactor;
newScale = newScale < minScale ? minScale : newScale;
Vector3 newScaleVector = new Vector3(newScale, newScale, newScale);
transform.localScale = newScaleVector;
}
public virtual void AppendVictim(GameObject victim)
{
if (!victims.Contains(victim))
{
victims.Add(victim);
}
}
public bool IsInvulnerable()
{
return deflectionBonus > 1f;
}
public int GetKills()
{
return victims.Count;
}
public string GetKillerName()
{
return killerName;
}
public int GetWeaponsCount()
{
return weaponCollection.Count;
}
public virtual void DropWeapon(NewRazerScript weapon)
{
weaponCollection.Remove(weapon);
ZoomInCamera();
RecalculateAngles();
}
protected virtual void HandleCollision(GameObject collisionGameObject)
{
if (collisionGameObject.tag == "weapon" && !isDead && !isPaused)
{
GameObject razer = collisionGameObject;
NewRazerScript razerScript = razer.GetComponent<NewRazerScript>();
if (razerScript.CanBeTaked(this))
{
AppendWeapon(razerScript);
}
if (razerScript.IsActiveState() && !razerScript.IsOwnersEqual(this))
{
float chanceToBeKilled = Random.Range(0, 1f);
if (chanceToBeKilled > deflectionBonus)
{
killer = razerScript.owner;
killerName = killer.characterName;
razerScript.AppendOwnerKill(gameObject);
HandleDeath();
}
}
}
}
protected virtual void HandleDeath(bool canResurrect = false)
{
//if (!gameHandler.IsGameEneded())
//{
//if (!canResurrect)
isDead = true;
if (SharedProperties.IsSoundsOn())
{
var randSoundIdx = Mathf.RoundToInt(Random.Range(0, deathSounds.Length - 1));
audioSource.PlayOneShot(deathSounds[randSoundIdx], 1f);
}
//}
leaderLightSystem.Stop();
lightSystem.Stop();
spriteHolder.enabled = false;
NewRazerScript[] collectionCopy = new NewRazerScript[weaponCollection.Count];
weaponCollection.CopyTo(collectionCopy);
for (int i = 0; i < collectionCopy.Length; i++)
{
if (collectionCopy[i] == null) continue;
NewRazerScript razerScript = collectionCopy[i];
float angle = razerScript.targetAngle - Mathf.PI / 2;
razerScript.ThrowOut(angle);
}
if (!canResurrect)
{
GetComponent<CircleCollider2D>().enabled = false;
gameHandler.DeathHandler();
gameHandler.HandleKill(this);
deathAnimator.Play();
}
else
{
ChangeLayer("OnlyBordersInteractable");
ResurrectView.ResurrectAcceptEvent += OnResurrectAccept;
}
}
private void ChangeLayer(string layerName)
{
gameObject.layer = LayerMask.NameToLayer(layerName);
}
private void OnResurrectAccept(bool accept)
{
ResurrectView.ResurrectAcceptEvent -= OnResurrectAccept;
isDead = !accept;
ThinkToResurrect = false;
if (accept)
{
//ChangeLayer("UnitLayer");
isTimerEnabled = true;
ApplySpell(new SpellModel(SpellType.IncSpeed, 40f, timerResurrectLayer));
ApplySpell(new SpellModel(SpellType.DeflectionChance, 110f, timerResurrectLayer));
spriteHolder.enabled = true;
GetComponent<CircleCollider2D>().enabled = true;
}
else
{
gameHandler.DeathHandler();
gameHandler.HandleKill(this);
deathAnimator.Play();
}
}
public void PlayRazerHitSound()
{
if (!SharedProperties.IsSoundsOn())
return;
if (!gameHandler.isNeedToDisableSounds)
{
var randSoundIdx = Mathf.RoundToInt(Random.Range(0, hitSounds.Length - 1));
audioSource.PlayOneShot(hitSounds[randSoundIdx], .3f);
}
}
public void PlayKnifeDragInBlackHoleSound()
{
if (!SharedProperties.IsSoundsOn())
return;
if (!gameHandler.isNeedToDisableSounds)
{
var randSoundIdx = Mathf.RoundToInt(Random.Range(0, hitSounds.Length - 1));
audioSource.PlayOneShot(dragInHoleSounds[randSoundIdx], .3f);
}
}
private void PlayRazerTakingSound()
{
if (!SharedProperties.IsSoundsOn())
return;
if (!gameHandler.isNeedToDisableSounds)
{
var randSoundIdx = Mathf.RoundToInt(Random.Range(0, takingSounds.Length - 1));
audioSource.PlayOneShot(takingSounds[randSoundIdx], .5f);
}
}
public void TurnOnLeaderLight()
{
lightSystem.Stop();
if (!isDead)
leaderLightSystem.Play();
}
public void TurnOffLeaderLight()
{
leaderLightSystem.Stop();
if (!isDead)
lightSystem.Play();
}
protected NewCharacterScript GetClosestEnemy()
{
var closestEnemies = gameHandler.GetCharsInRangeOfPosition(transform.position);
closestEnemies.Remove(this);
if (closestEnemies.Count > 0)
{
NewCharacterScript closestEnemy = closestEnemies[0];
var minDistanceToEnemy = Vector3.Distance(closestEnemy.transform.position, transform.position);
foreach (var enemy in closestEnemies)
{
var distanceToEnemy = Vector3.Distance(enemy.transform.position, transform.position);
if (distanceToEnemy < minDistanceToEnemy && enemy != this)
{
minDistanceToEnemy = distanceToEnemy;
closestEnemy = enemy;
}
}
return closestEnemy;
}
return null;
}
virtual protected void GetHaste(HasteScript hasteObject)
{
hasteDuration = hasteObject.hasteDuration + hasteObject.hasteDuration * bonusHasteDuration;
haste = hasteObject.hasteBonus;
Destroy(hasteObject.gameObject);
}
virtual protected void ApplySpells()
{
ApplySpell(uiModel.unitSpell);
ApplySpell(uiModel.knifeSpell);
}
virtual protected void ApplySpell(SpellModel spell)
{
switch (spell.spellType)
{
// Knife Spells at 9.10.2019
case SpellType.AttackRange:
attackRadiusBonus += spell.value / 100f;
break;
case SpellType.BlockRange:
blockRadiusBonus += spell.value / 100f;
break;
case SpellType.RotationSpeed:
OrbitScript orbit = orbitCenter.GetComponent<OrbitScript>();
orbit.rotatingSpeed += orbit.rotatingSpeed * (spell.value / 100f);
break;
// Unit Spells at 9.10.2019
case SpellType.DeflectionChance:
deflectionBonus += spell.value / 100f;
break;
case SpellType.HasteBonusTime:
bonusHasteDuration += spell.value / 100f;
break;
case SpellType.IncSpeed:
speed += speed * (spell.value / 100f);
break;
case SpellType.ParryChance:
case SpellType.KnivesAtStart:
case SpellType.None:
default:
break;
}
if(spell.Duration > 0)
{
Debug.Log("Начинает действовать бафф - " + spell.spellType + "! Время действия в секундах - " + spell.Duration);
spell.endTime = spell.Duration + Time.time;
timedSpells.Add(spell);
UpdateTimedSpells();
}
}
private void UpdateTimedSpells()
{
shortestTimeSpell = float.MaxValue;
for (int i = timedSpells.Count - 1; i >= 0 ; i--)
{
if (Time.time >= timedSpells[i].endTime)
{
Debug.Log("Бафф прекратил свое действие - " + timedSpells[i].spellType);
RemoveSpell(timedSpells[i]);
timedSpells.Remove(timedSpells[i]);
} else
{
shortestTimeSpell = shortestTimeSpell < timedSpells[i].endTime ? shortestTimeSpell : timedSpells[i].endTime;
}
}
}
virtual protected void RemoveSpell(SpellModel spell)
{
SpellModel invertedSpell = new SpellModel(spell.spellType, spell.value * -1);
ApplySpell(invertedSpell);
}
}