private IEnumerator ReleaseBottleScreamAsync() { _playerAnimation.PlayEmote(PlayerAnimatorController.EmoteState.OpenBottle); yield return(_playerAnimation.AnimatorCallbacks.WaitForEvent("OnBottleUncorked")); ScreamContainer bottle = _objectHolder.HeldObject.GetComponent <ScreamContainer>(); if (bottle != null && bottle.ScreamSounds.Count > 0) { ScreamDamageable.DoScream(bottle.ScreamSounds, bottle.transform.position, transform.forward, _screamDamageable); bottle.ReleaseScream(); } yield return(null); }
public static void DoScream(IReadOnlyList <ScreamSoundDefinition> screamSounds, Vector3 fromPos, Vector3 dir, ScreamDamageable ignore = null) { Debug.DrawRay(fromPos, dir * kScreamRange, Color.green, 1); for (int i = 0; i < _instances.Count; ++i) { ScreamDamageable damageable = _instances[i]; if (damageable == ignore) { continue; } Vector3 toDamageable = damageable.transform.position - fromPos; float angle = Vector3.Angle(dir.WithY(0), toDamageable.WithY(0)); float dist = toDamageable.magnitude; if ((dist < kScreamRange && angle < kScreamAngle) || dist < kScreamMinRange) { Debug.Log($"Screaming at {damageable.name}"); Debug.DrawRay(fromPos, toDamageable, Color.red, 10); damageable.NotifyScreamedAt(screamSounds); } } }
void OnBehaviorStateEntered(BehaviorState newBehavior) { switch (newBehavior) { case BehaviorState.Idle: _throttleUrgency = 0.0f; // stop _pathRefreshPeriod = -1.0f; // no refresh _idleDuration = Random.Range(IdleMinDuration, IdleMaxDuration); break; case BehaviorState.Wander: _throttleUrgency = 0.5f; // half speed _pathRefreshPeriod = -1.0f; // manual refresh // Pick a path to a wander target { Vector2 offset = Random.insideUnitCircle * WanderRange; Vector3 wanderTarget = _spawnLocation + Vector3.left * offset.x + Vector3.forward * offset.y; RecomputePathTo(wanderTarget); } break; case BehaviorState.Chase: _throttleUrgency = 1.0f; // full speed _pathRefreshPeriod = 2.0f; // refresh path every 2 seconds while persuing player // Force on line of sight checks even when player is out of vision cone _perceptionComponent.ForceLineOfSightCheck = true; // Start dropping player sanity while pursuit active GameStateManager.Instance.PlayerSanity.OnPursuitStarted(); // Head to the player // If this fails we take care of it in attack update RecomputePathTo(GetCurrentPlayerLocation()); break; case BehaviorState.Cower: _throttleUrgency = 0.0f; // Stop and sh*t yourself _pathRefreshPeriod = -1.0f; // manual refresh _aiAnimation.PlayEmote(AIAnimatorController.EmoteState.Cower); // Set animation dead flag early so that we don't leave emote state _aiAnimation.IsDead = true; // Hide the vision cone _perceptionComponent.gameObject.SetActive(false); break; case BehaviorState.Attack: _throttleUrgency = 0.0f; // Stop and attack in place _pathRefreshPeriod = -1.0f; // manual refresh _aiAnimation.PlayEmote(AIAnimatorController.EmoteState.Attack); _timeSinceAttack = 0.0f; // We just attacked var screamSounds = new List <ScreamSoundDefinition>() { _attackScream }; _screamController.StartScream(screamSounds, false, 1.0f); ScreamDamageable.DoScream(screamSounds, _perceptionComponent.transform.position, _perceptionComponent.transform.forward, _screamDamageable); break; case BehaviorState.Flee: _throttleUrgency = 1.0f; // full speed _pathRefreshPeriod = -1.0f; // manual refresh // Head back to spawn location // If this fails we take care of it in flee update RecomputePathTo(_spawnLocation); break; case BehaviorState.Dead: // Play death effects to cover the transition if (_deathFX != null) { Instantiate(_deathFX, transform.position, Quaternion.identity); } AudioManager.Instance.PlaySound(gameObject, _deathSound); // Spawn a death bottles in out place if (_deathBottleSpawn != null) { GameObject bottle = Instantiate(_deathBottleSpawn, transform.position, Quaternion.identity); ScreamContainer screamContainer = bottle.GetComponent <ScreamContainer>(); if (screamContainer != null) { screamContainer.FillScream(new List <ScreamSoundDefinition>() { _attackScream }); } } // Clean ourselves up after a moment Destroy(this, 0.1f); break; } }