Initial
This commit is contained in:
parent
7a77b79dc5
commit
cdadd75ee9
104 changed files with 9416 additions and 0 deletions
|
@ -0,0 +1,27 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using DunGen;
|
||||
|
||||
namespace ScarletMansion {
|
||||
public class FloorCleanUpParent : MonoBehaviour, IDungeonCompleteReceiver {
|
||||
|
||||
public FloorCleanup[] children;
|
||||
|
||||
void Reset(){
|
||||
children = GetComponentsInChildren<FloorCleanup>();
|
||||
}
|
||||
|
||||
public void OnDungeonComplete(Dungeon dungeon) {
|
||||
var anyChanges = true;
|
||||
while(anyChanges) {
|
||||
anyChanges = false;
|
||||
foreach(var c in children) anyChanges = anyChanges | c.UpdateRender();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ScarletMansion {
|
||||
public class FloorCleanup : MonoBehaviour {
|
||||
|
||||
[Header("References")]
|
||||
public MeshRenderer targetRenderer;
|
||||
public GameObject targerGameObject;
|
||||
public int bitValueCheck;
|
||||
|
||||
[Header("Logic")]
|
||||
public GameObject[] neighbors;
|
||||
|
||||
public int[] stateValues;
|
||||
public Material[] stateMaterials;
|
||||
public float[] stateRotations;
|
||||
|
||||
public State[] states;
|
||||
|
||||
[System.Serializable]
|
||||
public class State {
|
||||
public int value;
|
||||
public Material material;
|
||||
public float rotation;
|
||||
}
|
||||
|
||||
void Reset(){
|
||||
targetRenderer = GetComponent<MeshRenderer>();
|
||||
targerGameObject = gameObject;
|
||||
}
|
||||
|
||||
public bool UpdateRender(){
|
||||
|
||||
var value = 0;
|
||||
var maxValue = (1 << neighbors.Length) - 1;
|
||||
for(var i = 0; i < neighbors.Length; ++i){
|
||||
var n = neighbors[i];
|
||||
if (n != null && neighbors[i].activeSelf) value += 1 << i;
|
||||
}
|
||||
|
||||
if (value == maxValue) return false;
|
||||
|
||||
for(var i = 0; i < stateValues.Length; ++i){
|
||||
if (stateValues[i] == value) {
|
||||
targetRenderer.material = stateMaterials[i];
|
||||
targetRenderer.transform.localEulerAngles = new Vector3(0f, stateRotations[i], 0f);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var wasActive = targerGameObject.activeSelf;
|
||||
targerGameObject.SetActive(false);
|
||||
return wasActive;
|
||||
}
|
||||
|
||||
void OnDrawGizmosSelected(){
|
||||
Gizmos.color = Color.green;
|
||||
for(var i = 0; i < neighbors.Length; ++i){
|
||||
if ((bitValueCheck & (1 << i)) > 0) {
|
||||
Gizmos.DrawCube(neighbors[i].transform.position, Vector3.one);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ScarletMansion {
|
||||
|
||||
public class KnightSpawnPoint : MonoBehaviour {
|
||||
|
||||
public int index;
|
||||
|
||||
public void Start(){
|
||||
if (GameNetworkManager.Instance.isHostingGame)
|
||||
StartCoroutine(GetNearbyPlayers());
|
||||
}
|
||||
|
||||
public const float minTime = 4f;
|
||||
public const float maxTime = 8f;
|
||||
public const float minSqrDistance = 6f * 6f;
|
||||
|
||||
public IEnumerator GetNearbyPlayers(){
|
||||
while(true){
|
||||
var randomWait = UnityEngine.Random.Range(minTime, maxTime);
|
||||
yield return new WaitForSeconds(randomWait);
|
||||
|
||||
var sround = StartOfRound.Instance;
|
||||
var players = sround.allPlayerScripts;
|
||||
var playerCount = sround.connectedPlayersAmount + 1;
|
||||
for(var i = 0; i < playerCount; ++i){
|
||||
var player = players[i];
|
||||
if (!player.isPlayerControlled && player.isPlayerDead) continue;
|
||||
|
||||
// could i do a raycast?
|
||||
// i mean i could but most knights are in visable locations in every room
|
||||
// plus its a big pain on GOD
|
||||
var dist = Vector3.SqrMagnitude(transform.position - player.transform.position);
|
||||
if (dist <= minSqrDistance) {
|
||||
KnightSpawnManager.Instance.lastKnightSeenPlayer = index;
|
||||
Plugin.logger.LogInfo($"Knight {index} has noticed player {player.playerUsername}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using DunGen;
|
||||
|
||||
namespace ScarletMansion.Lights {
|
||||
|
||||
public class ScarletLight : MonoBehaviour, IComparable<ScarletLight>, IDungeonCompleteReceiver {
|
||||
|
||||
public Light light;
|
||||
public int priority = 0;
|
||||
|
||||
private Coroutine anger;
|
||||
private bool permenantAnger;
|
||||
|
||||
public int CompareTo(ScarletLight obj) {
|
||||
return obj.priority.CompareTo(priority);
|
||||
}
|
||||
|
||||
void Reset(){
|
||||
light = GetComponent<Light>();
|
||||
}
|
||||
|
||||
public void BeginAngry(float duration, bool forever){
|
||||
if (permenantAnger) return;
|
||||
if (anger != null) StopCoroutine(anger);
|
||||
|
||||
if (forever) permenantAnger = true;
|
||||
anger = StartCoroutine(AngerCoroutine(duration));
|
||||
}
|
||||
|
||||
private IEnumerator AngerCoroutine(float duration){
|
||||
var t = 0f;
|
||||
var c = light.color;
|
||||
while(t < 0.375f) {
|
||||
yield return null;
|
||||
t += Time.deltaTime;
|
||||
light.color = Color.Lerp(c, Color.red, t / 0.375f);
|
||||
}
|
||||
|
||||
if (permenantAnger) yield break;
|
||||
yield return new WaitForSeconds(duration + UnityEngine.Random.value);
|
||||
|
||||
c = light.color;
|
||||
t = 0f;
|
||||
while(t < 1.25f){
|
||||
yield return null;
|
||||
t += Time.deltaTime;
|
||||
light.color = Color.Lerp(c, Color.white, t / 1.25f);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void OnDungeonComplete(Dungeon dungeon) {
|
||||
if (!gameObject.activeInHierarchy) return;
|
||||
GamePatch.Managers.AngerManager.Instance.AddLight(this);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using DunGen;
|
||||
|
||||
namespace ScarletMansion.Lights {
|
||||
public class ScarletLightCleanup : MonoBehaviour, IDungeonCompleteReceiver {
|
||||
|
||||
public static float[] weights = new [] { 2f, 4f, 3f, 1f };
|
||||
public int maxLights = 2;
|
||||
|
||||
public void OnDungeonComplete(Dungeon dungeon) {
|
||||
|
||||
var lights = GetComponentsInChildren<ScarletLight>();
|
||||
|
||||
if (lights.Length == 0) return;
|
||||
|
||||
// the smallest amount of optimization
|
||||
var random = DunGenPatch.Patch.generatorInstance.RandomStream;
|
||||
if (lights.Length > 1){
|
||||
Utility.Shuffle(random, lights);
|
||||
System.Array.Sort(lights);
|
||||
}
|
||||
|
||||
//Plugin.logger.LogInfo(string.Join(", ", lights.Select(l => l.priority)));
|
||||
|
||||
var count = GetRandom(random, weights);
|
||||
count = Mathf.Min(count, maxLights);
|
||||
for(var i = count; i < lights.Length; ++i){
|
||||
lights[i].gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static int GetRandom(RandomStream random, float[] weights) {
|
||||
var total = 0f;
|
||||
foreach(var w in weights){
|
||||
total += w;
|
||||
}
|
||||
|
||||
var value = (float)random.NextDouble() * total;
|
||||
for(var i = 0; i < weights.Length; ++i){
|
||||
var w = weights[i];
|
||||
if (w == 0f) continue;
|
||||
|
||||
if (value < w) {
|
||||
return i;
|
||||
}
|
||||
value -= w;
|
||||
}
|
||||
|
||||
Plugin.logger.LogError("GetRandom for float[] failed. Defaulting to 0");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,247 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using Unity.Netcode;
|
||||
using DunGen;
|
||||
using ScarletMansion.Lights;
|
||||
using ScarletMansion.GamePatch.Managers;
|
||||
using GameNetcodeStuff;
|
||||
|
||||
namespace ScarletMansion.GamePatch.Components {
|
||||
public class ScarletBedroom : MonoBehaviour, IDungeonCompleteReceiver {
|
||||
|
||||
public static ActionList onBedroomEndEvent = new ActionList("onBedroomEnd");
|
||||
|
||||
[Header("References")]
|
||||
public ScarletVent vent;
|
||||
public Transform paintingSpawnTransform;
|
||||
public AudioSource screamAudioSource;
|
||||
public Transform[] itemSpawns;
|
||||
|
||||
private Light[] lights;
|
||||
private Doorway[] doorways;
|
||||
private ItemReference[] bonusItems;
|
||||
private EnemyReferenceSpawnLogic bonusEnemy;
|
||||
|
||||
const float spawnTime = 10f;
|
||||
const float cloudTime = 4f;
|
||||
|
||||
public void Anger(Transform target){
|
||||
AngerManager.Instance.Anger();
|
||||
StartCoroutine(PlayAudio());
|
||||
StartCoroutine(IncreaseVentAudio());
|
||||
StartCoroutine(LockDoorAndSpawnEnemy(target));
|
||||
|
||||
foreach(var l in lights){
|
||||
StartCoroutine(FlickerLight(l));
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator PlayAudio(){
|
||||
yield return new WaitForSeconds(UnityEngine.Random.Range(0.75f, 1f));
|
||||
screamAudioSource.Play();
|
||||
AngerManager.Instance.TriggerAngerLightBrief(6f);
|
||||
|
||||
var local = StartOfRound.Instance.localPlayerController;
|
||||
var dist = Vector3.SqrMagnitude(local.transform.position - transform.position);
|
||||
if (dist < 12f * 12f)
|
||||
local.JumpToFearLevel(0.75f);
|
||||
else if (dist < 24f * 24f)
|
||||
local.JumpToFearLevel(0.5f);
|
||||
else if (dist < 32f * 32f)
|
||||
local.JumpToFearLevel(0.25f);
|
||||
}
|
||||
|
||||
public IEnumerator LockDoorAndSpawnEnemy(Transform target){
|
||||
var roundmanager = RoundManager.Instance;
|
||||
var doors = new List<ScarletDoor>();
|
||||
|
||||
// lock doors
|
||||
if (roundmanager.IsServer){
|
||||
foreach(var d in doorways){
|
||||
var result = AngerManager.Instance.GetScarletDoor(d.transform.position);
|
||||
if (result) doors.Add(result);
|
||||
}
|
||||
|
||||
foreach(var d in doors){
|
||||
d.LockDoorClientRpc();
|
||||
}
|
||||
}
|
||||
|
||||
yield return new WaitForSeconds(spawnTime);
|
||||
|
||||
SpawnRandomEnemy(target);
|
||||
SpawnLoot();
|
||||
|
||||
onBedroomEndEvent.Call();
|
||||
|
||||
// stop volume stuff
|
||||
vent.OpenVentClientRpc();
|
||||
vent.shakeAudioSource.Stop();
|
||||
vent.shakeAudioSource.volume = 0f;
|
||||
|
||||
// unlock doors
|
||||
if (roundmanager.IsServer){
|
||||
foreach(var d in doors){
|
||||
d.UnlockDoorClientRpc();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator IncreaseVentAudio(){
|
||||
yield return new WaitForSeconds(1f);
|
||||
|
||||
vent.shakeAudioSource.Play();
|
||||
var t = 0f;
|
||||
while (t < cloudTime){
|
||||
vent.shakeAudioSource.volume = t / cloudTime;
|
||||
t += Time.deltaTime;
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator FlickerLight(Light light){
|
||||
// gives time for player to react to their environment
|
||||
yield return new WaitForSeconds(UnityEngine.Random.Range(1f, 1.5f));
|
||||
|
||||
// scarlet lights flicker
|
||||
var isScarletLight = light.GetComponent<ScarletLight>() != null;
|
||||
if (isScarletLight){
|
||||
var count = UnityEngine.Random.Range(6, 8);
|
||||
for (var i = 0; i < count; ++i) {
|
||||
light.enabled = false;
|
||||
yield return new WaitForSeconds(UnityEngine.Random.Range(0.15f, 0.25f) * (1f - count * 0.05f));
|
||||
light.enabled = true;
|
||||
yield return new WaitForSeconds(UnityEngine.Random.Range(0.5f, 0.6f) * (1f - count * 0.05f));
|
||||
}
|
||||
|
||||
light.enabled = false;
|
||||
}
|
||||
// normal lights are candles, so just turn them off
|
||||
else {
|
||||
yield return new WaitForSeconds(UnityEngine.Random.Range(3f, 5f));
|
||||
light.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<EnemyReferenceSpawnLogic> spawnableEnemiesTrueList;
|
||||
|
||||
public static void CreateRandomEnemyList(List<SpawnableEnemyWithRarity> enemies){
|
||||
var lower = PluginConfig.Instance.paintingEnemyListValue.ToLowerInvariant();
|
||||
if (lower == "default"){
|
||||
lower = "knight@s1,crawler,nutcracker,springman,maskedplayerenemy,jester@s1";
|
||||
}
|
||||
|
||||
spawnableEnemiesTrueList = new List<EnemyReferenceSpawnLogic>();
|
||||
var entries = Utility.ParseString(lower, new string[] {","}, new string[] {"@"} );
|
||||
for(var i = 0; i < enemies.Count; ++i){
|
||||
var enemyType = enemies[i].enemyType;
|
||||
var enemyName = enemyType.name.ToLowerInvariant();
|
||||
var enemyDisplayName = enemyType.enemyName.ToLowerInvariant();
|
||||
|
||||
var link = entries.FirstOrDefault(e => e.main == enemyName || e.main == enemyDisplayName);
|
||||
if (link != null){
|
||||
EnemyReferenceSpawnLogic.SpawnLogic spawnValue;
|
||||
var spawnTag = link.GetParameter("s");
|
||||
if (spawnTag != null) spawnValue = (EnemyReferenceSpawnLogic.SpawnLogic)Utility.TryParseInt(spawnTag.Substring(1), 0);
|
||||
else spawnValue = 0;
|
||||
|
||||
var reference = new EnemyReferenceSpawnLogic(enemyType, i, spawnValue);
|
||||
spawnableEnemiesTrueList.Add(reference);
|
||||
Plugin.logger.LogInfo($"Added {reference.ToString()} to bedroom event");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public EnemyReferenceSpawnLogic GetRandomEnemy(System.Random sysRandom){
|
||||
var roundManager = RoundManager.Instance;
|
||||
if (!roundManager.IsServer) return null;
|
||||
if (!PluginConfig.Instance.paintingSpawnEnemyValue) return null;
|
||||
|
||||
if (spawnableEnemiesTrueList == null || spawnableEnemiesTrueList.Count == 0){
|
||||
Plugin.logger.LogError($"Could not select enemy to spawn in bedroom. Empty enemy list?");
|
||||
return null;
|
||||
}
|
||||
|
||||
var index = sysRandom.Next(spawnableEnemiesTrueList.Count);
|
||||
var enemy = spawnableEnemiesTrueList[index];
|
||||
Plugin.logger.LogInfo($"Selected enemy to spawn {enemy.ToString()}");
|
||||
return enemy;
|
||||
}
|
||||
|
||||
public void SpawnRandomEnemy(Transform target, int overrideIndex = -1){
|
||||
var roundmanager = RoundManager.Instance;
|
||||
if (!roundmanager.IsHost) return;
|
||||
if (bonusEnemy == null) return;
|
||||
|
||||
try {
|
||||
|
||||
var enemy = bonusEnemy.enemy;
|
||||
var enemyIndex = bonusEnemy.index;
|
||||
|
||||
if (enemyIndex > -1){
|
||||
var pos = vent.transform.position;
|
||||
var dir = target.transform.position - pos;
|
||||
dir.y = 0f;
|
||||
var rot = Quaternion.LookRotation(dir);
|
||||
var y = rot.eulerAngles.y;
|
||||
|
||||
bonusEnemy.ApplySpawnLogic();
|
||||
|
||||
roundmanager.currentEnemyPower += enemy.PowerLevel;
|
||||
roundmanager.SpawnEnemyServerRpc(vent.transform.position, y, enemyIndex);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
var enemyString = bonusEnemy != null ? bonusEnemy.ToString() : "NULL";
|
||||
Plugin.logger.LogError($"Failed to spawn enemy for bedroom event, the smelly culprit is {enemyString}");
|
||||
Plugin.logger.LogError(e.ToString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void SpawnLoot(){
|
||||
var roundmanager = RoundManager.Instance;
|
||||
if (!roundmanager.IsServer) return;
|
||||
|
||||
try {
|
||||
AngerManager.Instance.SpawnAngerLoot(bonusItems, itemSpawns);
|
||||
} catch (Exception e) {
|
||||
var itemStrings = string.Join("\n", bonusItems.Select(i => i != null ? i.ToString() : "NULL"));
|
||||
Plugin.logger.LogError($"Failed to spawn items for bedroom event, the smelly culprits are {itemStrings}");
|
||||
Plugin.logger.LogError(e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public void OnDungeonComplete(Dungeon dungeon) {
|
||||
AngerManager.Instance.AddBedroom(this);
|
||||
|
||||
var parent = GetComponentInParent<Tile>();
|
||||
lights = parent.GetComponentsInChildren<Light>();
|
||||
doorways = parent.UsedDoorways.ToArray();
|
||||
|
||||
var dunRandom = DunGenPatch.Patch.generatorInstance.RandomStream;
|
||||
var randomValue = (int)(dunRandom.NextDouble() * int.MaxValue);
|
||||
var sysRandom = new System.Random(randomValue);
|
||||
|
||||
Utility.Shuffle(sysRandom, itemSpawns);
|
||||
var count = sysRandom.Next(PluginConfig.Instance.paintingExtraLootValue.min, PluginConfig.Instance.paintingExtraLootValue.max + 1);
|
||||
|
||||
bonusItems = AngerManager.Instance.CreateAngerLoot(count, sysRandom);
|
||||
bonusEnemy = GetRandomEnemy(sysRandom);
|
||||
}
|
||||
|
||||
public void OnTriggerEnter(Collider other){
|
||||
Plugin.logger.LogInfo(other.gameObject.tag);
|
||||
if (other.gameObject.tag == "Player"){
|
||||
var player = other.gameObject.GetComponent<PlayerControllerB>();
|
||||
if (player && player.IsLocalPlayer){
|
||||
HUDManager.Instance.DisplayTip("SDM Dungeon Events", "Paintings fetch a good price, if you are daring...", false, true, "SDM_Bedroom");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using Unity.Netcode;
|
||||
|
||||
namespace ScarletMansion.GamePatch.Components {
|
||||
public class ScarletClock : NetworkBehaviour {
|
||||
|
||||
[Header("Animations")]
|
||||
public Vector3 eulerAngleOffset = new Vector3(-90f, -90f, -90f);
|
||||
public Transform hourHand;
|
||||
public Transform minuteHand;
|
||||
private Coroutine animationCoroutine;
|
||||
private int lastHour = -1;
|
||||
private int lastTotalMinutes = -1;
|
||||
|
||||
[Header("Sounds")]
|
||||
public AudioSource audioSource;
|
||||
public AudioClip[] audioClips;
|
||||
|
||||
[Header("Destruction Values")]
|
||||
public bool stop;
|
||||
public float chanceEveryHourToDestroy = 1f / 52f;
|
||||
private float timerTillDestroyed = -1f;
|
||||
|
||||
void Update(){
|
||||
|
||||
if (stop) return;
|
||||
|
||||
if (IsServer && timerTillDestroyed > 0f){
|
||||
timerTillDestroyed -= Time.deltaTime;
|
||||
if (timerTillDestroyed <= 0f) {
|
||||
StopClockClientRpc();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var timeOfDay = TimeOfDay.Instance;
|
||||
var totalMinutes = (int)(timeOfDay.normalizedTimeOfDay * (60f * timeOfDay.numberOfHours)) + 360;
|
||||
var hours = Mathf.FloorToInt(totalMinutes / 60f);
|
||||
var minutes = totalMinutes % 60;
|
||||
|
||||
var timeChanged = lastTotalMinutes != totalMinutes;
|
||||
var hourChanged = lastHour != hours;
|
||||
|
||||
if (timeChanged) {
|
||||
if (animationCoroutine != null) StopCoroutine(animationCoroutine);
|
||||
animationCoroutine = StartCoroutine(MoveHands(hours, minutes));
|
||||
}
|
||||
|
||||
if (IsServer && hourChanged){
|
||||
HourlySelfDestroyCheck();
|
||||
}
|
||||
|
||||
lastHour = hours;
|
||||
lastTotalMinutes = totalMinutes;
|
||||
}
|
||||
|
||||
// 60 = -90
|
||||
// 07 = -45
|
||||
// 15 = 0
|
||||
// 22 = 45
|
||||
|
||||
|
||||
// 12 = -90
|
||||
// 01 = -45
|
||||
// 03 = 0
|
||||
// 04 = 45
|
||||
|
||||
public IEnumerator MoveHands(int hour, int minutes){
|
||||
var currentHourHandRotation = hourHand.localRotation;
|
||||
var currentMinuteHandRotation = minuteHand.localRotation;
|
||||
|
||||
var nextHourHandAngles = eulerAngleOffset + new Vector3(hour / 12f * 360f, 0f, 0f);
|
||||
var nextHourHandRotation = Quaternion.Euler(nextHourHandAngles);
|
||||
|
||||
var nextMinuteHandAngles = eulerAngleOffset + new Vector3(minutes / 60f * 360f, 0f, 0f);
|
||||
var nextMinuteHandRotation = Quaternion.Euler(nextMinuteHandAngles);
|
||||
|
||||
//Plugin.logger.LogInfo($"({hour}: {minutes}): ({nextHourHandAngles.x}, {nextMinuteHandRotation.x})");
|
||||
|
||||
PlayAudio();
|
||||
|
||||
var t = 0f;
|
||||
var atimer = 0.3f;
|
||||
while(t < atimer) {
|
||||
yield return null;
|
||||
t += Time.deltaTime;
|
||||
|
||||
hourHand.localRotation = Quaternion.Slerp(currentHourHandRotation, nextHourHandRotation, t / atimer);
|
||||
minuteHand.localRotation = Quaternion.Slerp(currentMinuteHandRotation, nextMinuteHandRotation, t / atimer);
|
||||
}
|
||||
}
|
||||
|
||||
public void PlayAudio(){
|
||||
var clip = audioClips[UnityEngine.Random.Range(0, audioClips.Length)];
|
||||
audioSource.pitch = UnityEngine.Random.value * 0.3f + 0.85f;
|
||||
audioSource.PlayOneShot(clip);
|
||||
WalkieTalkie.TransmitOneShotAudio(audioSource, clip);
|
||||
}
|
||||
|
||||
public void HourlySelfDestroyCheck(){
|
||||
if (stop || timerTillDestroyed > 0) return;
|
||||
|
||||
Plugin.logger.LogInfo("Hourly clock self-destroy check");
|
||||
if (UnityEngine.Random.value < chanceEveryHourToDestroy) {
|
||||
timerTillDestroyed = UnityEngine.Random.value * 60f + 15f;
|
||||
Plugin.logger.LogInfo($"Clock offing itself in {timerTillDestroyed} sec");
|
||||
}
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
public void StopClockClientRpc(){
|
||||
stop = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using Unity.Netcode;
|
||||
using UnityEngine.AI;
|
||||
using ScarletMansion.GamePatch.Managers;
|
||||
|
||||
namespace ScarletMansion.GamePatch.Components {
|
||||
public class ScarletDoor : NetworkBehaviour {
|
||||
|
||||
[Header("Door Reference")]
|
||||
public DoorLock door;
|
||||
|
||||
[Header("Personal Refs")]
|
||||
public NavMeshObstacle obstacle;
|
||||
public BoxCollider boxCollider;
|
||||
public ParticleSystem ps;
|
||||
|
||||
private bool previousDoorLockValue;
|
||||
|
||||
void Awake(){
|
||||
AngerManager.Instance.AddDoor(this);
|
||||
}
|
||||
|
||||
[ServerRpc]
|
||||
public void LockDoorServerRpc(){
|
||||
LockDoorClientRpc();
|
||||
}
|
||||
|
||||
[ServerRpc]
|
||||
public void UnlockDoorServerRpc(){
|
||||
UnlockDoorClientRpc();
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
public void LockDoorClientRpc(){
|
||||
if (door){
|
||||
door.isDoorOpened = false;
|
||||
door.navMeshObstacle.enabled = true;
|
||||
|
||||
if (RoundManager.Instance.IsServer)
|
||||
door.GetComponent<AnimatedObjectTrigger>().TriggerAnimationNonPlayer(false, true, true);
|
||||
|
||||
door.doorTrigger.interactable = false;
|
||||
previousDoorLockValue = door.isLocked;
|
||||
door.isLocked = true;
|
||||
}
|
||||
|
||||
obstacle.enabled = true;
|
||||
boxCollider.enabled = true;
|
||||
ps.Play();
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
public void UnlockDoorClientRpc(){
|
||||
if (door){
|
||||
door.doorTrigger.interactable = true;
|
||||
door.isLocked = previousDoorLockValue;
|
||||
}
|
||||
|
||||
obstacle.enabled = false;
|
||||
boxCollider.enabled = false;
|
||||
ps.Stop();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,207 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using Unity.Netcode;
|
||||
|
||||
namespace ScarletMansion.GamePatch.Components {
|
||||
public class ScarletDoorLock : DoorLock {
|
||||
|
||||
public static float internalTimerCooldown = 1f;
|
||||
|
||||
[Header("Scarlet")]
|
||||
public List<GameObject> healthTilePieces;
|
||||
public List<GameObject> frameTilePieces;
|
||||
private int healthTilePiecesCount;
|
||||
public GameObject propPrefab;
|
||||
|
||||
[Header("Audio")]
|
||||
public AudioSource audioSource;
|
||||
public AudioClip[] destroyAudioClips;
|
||||
public AudioClip fullyDestroyedAudioClip;
|
||||
|
||||
[Header("Proper Disable Logic")]
|
||||
public Collider[] disableColliders;
|
||||
public Animator disableAnimator;
|
||||
public bool callNormalScript;
|
||||
|
||||
private float nextInternalTimer = 0f;
|
||||
private float destroyMeter = 0f;
|
||||
private int currentDamage = 0;
|
||||
|
||||
public void AwakeScarlet(){
|
||||
healthTilePiecesCount = healthTilePieces.Count + 1;
|
||||
}
|
||||
|
||||
void Start(){
|
||||
if (IsOwner){
|
||||
var randomCheck = UnityEngine.Random.value < 0.1f;
|
||||
if (randomCheck){
|
||||
ApplyDamageServerRpc(Vector3.forward, 50f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnTriggerStayScarlet(Collider other){
|
||||
if (NetworkManager.Singleton == null || !base.IsServer) return;
|
||||
if (isDoorOpened || !doorTrigger.interactable) return;
|
||||
|
||||
if (other.tag == "Enemy"){
|
||||
var comp = other.GetComponent<EnemyAICollisionDetect>();
|
||||
if (comp == null) return;
|
||||
|
||||
// do normal door opening script
|
||||
var enemyScript = comp.mainScript;
|
||||
if (IsInOpenDoorNormallyState(enemyScript)) {
|
||||
callNormalScript = true;
|
||||
OnTriggerStay(other);
|
||||
return;
|
||||
}
|
||||
|
||||
var direction = transform.position - comp.transform.position;
|
||||
direction.y = 0f;
|
||||
direction = direction.normalized;
|
||||
|
||||
var timeDelta = Time.deltaTime * GetDoorDamagePerSecond(enemyScript);
|
||||
if (isLocked) timeDelta *= PluginConfig.Instance.lockedDoorEnemyDamageMultiplierValue;
|
||||
destroyMeter += timeDelta;
|
||||
|
||||
ApplyDoorPieceDamage(direction);
|
||||
}
|
||||
}
|
||||
|
||||
static readonly Dictionary<Type, Func<EnemyAI, bool>> EnemyToDoorOpen = new Dictionary<Type, Func<EnemyAI, bool>>(){
|
||||
{ typeof(CentipedeAI), (e) => e.currentBehaviourStateIndex <= 1 },
|
||||
{ typeof(CrawlerAI), (e) => e.currentBehaviourStateIndex == 0 },
|
||||
{ typeof(FlowermanAI), (e) => e.currentBehaviourStateIndex <= 1 },
|
||||
{ typeof(HoarderBugAI), (e) => e.currentBehaviourStateIndex <= 1 },
|
||||
{ typeof(JesterAI), (e) => e.currentBehaviourStateIndex <= 1 },
|
||||
{ typeof(MaskedPlayerEnemy), (e) => e.currentBehaviourStateIndex == 0 },
|
||||
{ typeof(NutcrackerEnemyAI), (e) => e.currentBehaviourStateIndex <= 1 },
|
||||
{ typeof(PufferAI), (e) => e.currentBehaviourStateIndex == 0 },
|
||||
{ typeof(SandSpiderAI), (e) => e.currentBehaviourStateIndex <= 1 },
|
||||
{ typeof(SpringManAI), (e) => e.currentBehaviourStateIndex == 0 },
|
||||
{ typeof(KnightVariant), (e) => e.currentBehaviourStateIndex == 0 },
|
||||
};
|
||||
|
||||
static readonly Dictionary<Type, float> EnemyDoorDamagePerSecond = new Dictionary<Type, float>(){
|
||||
{ typeof(BlobAI), 6.25f },
|
||||
{ typeof(CentipedeAI), 25f },
|
||||
{ typeof(CrawlerAI), 50f },
|
||||
{ typeof(DressGirlAI), 50f },
|
||||
{ typeof(FlowermanAI), 50f },
|
||||
{ typeof(HoarderBugAI), 50f },
|
||||
{ typeof(JesterAI), 50f },
|
||||
{ typeof(MaskedPlayerEnemy), 50f },
|
||||
{ typeof(NutcrackerEnemyAI), 50f },
|
||||
{ typeof(PufferAI), 25f },
|
||||
{ typeof(SandSpiderAI), 25f },
|
||||
{ typeof(SpringManAI), 12.5f },
|
||||
{ typeof(KnightVariant), 12.5f },
|
||||
};
|
||||
|
||||
public bool IsInOpenDoorNormallyState(EnemyAI enemy){
|
||||
var type = enemy.GetType();
|
||||
if (EnemyToDoorOpen.ContainsKey(type)) return EnemyToDoorOpen[type](enemy);
|
||||
return false;
|
||||
}
|
||||
|
||||
public float GetDoorDamagePerSecond(EnemyAI enemy){
|
||||
var type = enemy.GetType();
|
||||
if (EnemyDoorDamagePerSecond.ContainsKey(type)) return EnemyDoorDamagePerSecond[type];
|
||||
return enemy.openDoorSpeedMultiplier * 100f;
|
||||
}
|
||||
|
||||
public void ApplyDoorPieceDamage(Vector3 direction, bool ignoreInternalTimer = false){
|
||||
// full destruction
|
||||
if (destroyMeter >= 100f) DestroyAndOpenDoorServerRpc(direction);
|
||||
|
||||
// health destruction
|
||||
var passesTimeVibeCheck = ignoreInternalTimer || Time.time >= nextInternalTimer;
|
||||
if (passesTimeVibeCheck && healthTilePieces.Count > 0) {
|
||||
var newDamage = Mathf.FloorToInt(destroyMeter * healthTilePiecesCount) / 100;
|
||||
var damageDiff = newDamage - currentDamage;
|
||||
if (damageDiff > 0) {
|
||||
DestroyDoorHealthPiecesClientRpc(newDamage - currentDamage, direction);
|
||||
nextInternalTimer = Time.time + internalTimerCooldown;
|
||||
currentDamage = newDamage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ServerRpc(RequireOwnership = false)]
|
||||
public void ApplyDamageServerRpc(Vector3 direction, float damage){
|
||||
destroyMeter += damage;
|
||||
ApplyDoorPieceDamage(direction, true);
|
||||
}
|
||||
|
||||
[ServerRpc(RequireOwnership = false)]
|
||||
public void DestroyAndOpenDoorServerRpc(Vector3 direction){
|
||||
Plugin.logger.LogInfo("Destro time");
|
||||
OpenDoorAsEnemyClientRpc();
|
||||
DestroyDoorClientRpc(direction);
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
public void DestroyDoorClientRpc(Vector3 direction){
|
||||
DestroyDoorPieces(healthTilePieces, healthTilePieces.Count, direction);
|
||||
DestroyDoorPieces(frameTilePieces, frameTilePieces.Count, direction);
|
||||
PlayAudio(fullyDestroyedAudioClip);
|
||||
|
||||
disableAnimator.enabled = false;
|
||||
foreach(var c in disableColliders){
|
||||
c.enabled = false;
|
||||
}
|
||||
|
||||
//doorTrigger.interactable = false;
|
||||
//doorTrigger.disabledHoverTip = string.Empty;
|
||||
|
||||
isLocked = false;
|
||||
isDoorOpened = true;
|
||||
navMeshObstacle.enabled = false;
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
public void DestroyDoorHealthPiecesClientRpc(int count, Vector3 direction){
|
||||
DestroyDoorPieces(healthTilePieces, count, direction);
|
||||
PlayAudio(destroyAudioClips[UnityEngine.Random.Range(0, destroyAudioClips.Length)]);
|
||||
}
|
||||
|
||||
public void DestroyDoorPieces(List<GameObject> tilePieces, int count, Vector3 direction){
|
||||
while(count > 0 && tilePieces.Count > 0){
|
||||
var lastIndex = tilePieces.Count - 1;
|
||||
var target = tilePieces[lastIndex];
|
||||
|
||||
var prop = Instantiate(propPrefab);
|
||||
prop.GetComponent<ScarletProp>().CreateProp(target, direction);
|
||||
target.SetActive(false);
|
||||
|
||||
tilePieces.RemoveAt(lastIndex);
|
||||
count--;
|
||||
}
|
||||
}
|
||||
|
||||
public void PlayAudio(AudioClip clip){
|
||||
audioSource.PlayOneShot(clip);
|
||||
WalkieTalkie.TransmitOneShotAudio(audioSource, clip);
|
||||
}
|
||||
|
||||
public static bool ScarletDoorRaycast(GrabbableObject __instance, Vector3 position, Vector3 forward, float distance, out ScarletDoorLock door){
|
||||
door = null;
|
||||
var isPlayerHolding = __instance.isHeld && __instance.playerHeldBy == GameNetworkManager.Instance.localPlayerController;
|
||||
var isServerCheck = __instance.IsServer && !isPlayerHolding;
|
||||
if (!isPlayerHolding && !isServerCheck) return false;
|
||||
|
||||
var ray = new Ray(position, forward);
|
||||
var layer = 1 << LayerMask.NameToLayer("InteractableObject");
|
||||
if (Physics.Raycast(ray, out var hit, distance, layer, QueryTriggerInteraction.Ignore)) {
|
||||
door = hit.transform.GetComponent<ScarletDoorLock>();
|
||||
return door != null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using GameNetcodeStuff;
|
||||
|
||||
namespace ScarletMansion.GamePatch.Components {
|
||||
public class ScarletFireExit : MonoBehaviour {
|
||||
|
||||
public bool enablePortalAnimation;
|
||||
|
||||
[Header("Animations")]
|
||||
public MeshRenderer portalRenderer;
|
||||
public MeshRenderer blackRenderer;
|
||||
|
||||
private Material portalMaterial;
|
||||
private Material blackMaterial;
|
||||
private Coroutine timerCoroutine;
|
||||
private Coroutine currentCoroutine;
|
||||
|
||||
public const float animationTime = 0.4f;
|
||||
|
||||
void Start(){
|
||||
portalMaterial = portalRenderer.material;
|
||||
blackMaterial = blackRenderer.material;
|
||||
}
|
||||
|
||||
public void DisableEnablePortal(){
|
||||
if (!enablePortalAnimation) return;
|
||||
|
||||
if (timerCoroutine != null) StopCoroutine(timerCoroutine);
|
||||
timerCoroutine = StartCoroutine(DisableEnablePortalCoroutine());
|
||||
}
|
||||
|
||||
private IEnumerator DisableEnablePortalCoroutine(){
|
||||
DisablePortal();
|
||||
yield return new WaitForSeconds(3f);
|
||||
EnablePortal();
|
||||
}
|
||||
|
||||
public void DisablePortal(){
|
||||
if (currentCoroutine != null) StopCoroutine(currentCoroutine);
|
||||
currentCoroutine = StartCoroutine(SetPortalCoroutine(-0.5f, 0f));
|
||||
}
|
||||
|
||||
public void EnablePortal(){
|
||||
if (currentCoroutine != null) StopCoroutine(currentCoroutine);
|
||||
currentCoroutine = StartCoroutine(SetPortalCoroutine(1.5f, 1f));
|
||||
}
|
||||
|
||||
private IEnumerator SetPortalCoroutine(float dissolveTarget, float blackTarget){
|
||||
float dv;
|
||||
Color bv;
|
||||
do {
|
||||
dv = portalMaterial.GetFloat("_DissolveValue");
|
||||
dv = Mathf.MoveTowards(dv, dissolveTarget, 2f / animationTime * Time.deltaTime);
|
||||
portalMaterial.SetFloat("_DissolveValue", dv);
|
||||
|
||||
bv = blackMaterial.color;
|
||||
bv.a = Mathf.MoveTowards(bv.a, blackTarget, 1f / animationTime * Time.deltaTime);
|
||||
blackMaterial.color = bv;
|
||||
|
||||
yield return null;
|
||||
} while (dv != dissolveTarget && bv.a != blackTarget);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using Unity.Netcode;
|
||||
using GameNetcodeStuff;
|
||||
|
||||
namespace ScarletMansion.GamePatch.Components {
|
||||
public class ScarletFrame : NetworkBehaviour {
|
||||
|
||||
//public MeshRenderer renderer;
|
||||
//public Material[] materials;
|
||||
|
||||
public void OnInteract(PlayerControllerB player){
|
||||
var direction = player.transform.position - transform.position;
|
||||
direction.y = 0f;
|
||||
|
||||
ChangeDirection(direction);
|
||||
ChangeDirectionServerRpc(direction);
|
||||
}
|
||||
|
||||
/*
|
||||
[ClientRpc]
|
||||
public void UpdateMaterialClientRpc(int value){
|
||||
var mats = new List<Material>(2);
|
||||
renderer.GetMaterials(mats);
|
||||
|
||||
mats[1] = materials[value % materials.Length];
|
||||
renderer.SetMaterials(mats);
|
||||
}
|
||||
*/
|
||||
|
||||
[ServerRpc(RequireOwnership = false)]
|
||||
public void ChangeDirectionServerRpc(Vector3 direction){
|
||||
ChangeDirectionClientRpc(direction);
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
public void ChangeDirectionClientRpc(Vector3 direction){
|
||||
ChangeDirection(direction);
|
||||
}
|
||||
|
||||
public void ChangeDirection(Vector3 direction){
|
||||
transform.rotation = Quaternion.LookRotation(direction);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.HighDefinition;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.InputSystem.Controls;
|
||||
|
||||
/*
|
||||
|
||||
namespace ScarletMansion {
|
||||
public class ScarletHDRISky : ScarletLighting {
|
||||
|
||||
public Volume volume;
|
||||
|
||||
public HDRISky GetSky(){
|
||||
volume.sharedProfile.TryGet<HDRISky>(out var sky);
|
||||
return sky;
|
||||
}
|
||||
|
||||
public VisualEnvironment GetEnv(){
|
||||
volume.sharedProfile.TryGet<VisualEnvironment>(out var env);
|
||||
return env;
|
||||
}
|
||||
|
||||
public override void DisableLights() {
|
||||
volume.enabled = false;
|
||||
}
|
||||
|
||||
public override void UpdateLight(float ratio) {
|
||||
GetSky().multiplier.value = valueRatio;
|
||||
GetEnv().skyAmbientMode.value = skyMode;
|
||||
volume.enabled = trueEnabled;
|
||||
}
|
||||
|
||||
public int value = 100;
|
||||
public float valueRatio = 1f;
|
||||
|
||||
public bool trueEnabled = true;
|
||||
public SkyAmbientMode skyMode = SkyAmbientMode.Dynamic;
|
||||
|
||||
void Update(){
|
||||
int direction = 0;
|
||||
if (IfKeyPress(Keyboard.current.minusKey, Keyboard.current.numpadMinusKey)){
|
||||
direction = -1;
|
||||
} else if (IfKeyPress(Keyboard.current.equalsKey, Keyboard.current.numpadPlusKey)){
|
||||
direction = 1;
|
||||
}
|
||||
|
||||
if (IfKeyPress(Keyboard.current.backspaceKey)){
|
||||
trueEnabled = !trueEnabled;
|
||||
Plugin.logger.LogInfo(trueEnabled);
|
||||
}
|
||||
|
||||
if (IfKeyPress(Keyboard.current.digit0Key, Keyboard.current.numpad0Key)){
|
||||
if (skyMode == SkyAmbientMode.Dynamic) skyMode = SkyAmbientMode.Static;
|
||||
else skyMode = SkyAmbientMode.Dynamic;
|
||||
Plugin.logger.LogInfo(skyMode);
|
||||
}
|
||||
|
||||
if (direction != 0){
|
||||
value = Mathf.Clamp(value + direction * 5, -100, 200);
|
||||
valueRatio = value * 0.01f;
|
||||
Plugin.logger.LogInfo(value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool IfKeyPress(params KeyControl[] keys){
|
||||
foreach(var k in keys){
|
||||
if (k.wasPressedThisFrame) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
*/
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
/*
|
||||
|
||||
namespace ScarletMansion {
|
||||
public abstract class ScarletLighting : MonoBehaviour {
|
||||
|
||||
public abstract void UpdateLight(float ratio);
|
||||
public abstract void DisableLights() ;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
|
@ -0,0 +1,46 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using GameNetcodeStuff;
|
||||
|
||||
namespace ScarletMansion.GamePatch.Components {
|
||||
public class ScarletPlayerControllerB : MonoBehaviour {
|
||||
|
||||
public PlayerControllerB player;
|
||||
|
||||
public void Initialize(PlayerControllerB player){
|
||||
this.player = player;
|
||||
CreateHelmetForFlashlight(player, Assets.flashlight, 0);
|
||||
CreateHelmetForFlashlight(player, Assets.flashlightBB, 1);
|
||||
}
|
||||
|
||||
public static void CreateHelmetForFlashlight(PlayerControllerB player, Assets.Flashlight flashlight, int index){
|
||||
try {
|
||||
var helmetLights = player.allHelmetLights.ToList();
|
||||
var light = helmetLights[index];
|
||||
var parent = light.transform.parent;
|
||||
var gameObj = GameObject.Instantiate(light.gameObject, parent);
|
||||
gameObj.name = $"scarletlight{index}";
|
||||
|
||||
var newFlashlightHelmetIndex = helmetLights.Count;
|
||||
|
||||
if (flashlight.scarletHelmetIndex != newFlashlightHelmetIndex)
|
||||
Plugin.logger.LogInfo($"Created helmet light for scarlet flashlight {index}. Updated index from {flashlight.scarletHelmetIndex} to {newFlashlightHelmetIndex}");
|
||||
|
||||
flashlight.scarletHelmetIndex = newFlashlightHelmetIndex;
|
||||
helmetLights.Add(gameObj.GetComponent<Light>());
|
||||
player.allHelmetLights = helmetLights.ToArray();
|
||||
|
||||
} catch (Exception e) {
|
||||
Plugin.logger.LogError("Failed to create helmet light for scarlet flashlight");
|
||||
Plugin.logger.LogError(e.ToString());
|
||||
|
||||
flashlight.scarletHelmetIndex = index;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
namespace ScarletMansion.GamePatch.Components {
|
||||
public class ScarletProp : MonoBehaviour {
|
||||
|
||||
[Header("References")]
|
||||
public MeshFilter meshFilter;
|
||||
public MeshRenderer meshRenderer;
|
||||
public MeshCollider meshCollider;
|
||||
public Rigidbody rigidbody;
|
||||
|
||||
public static float minForce = 4f;
|
||||
public static float maxForce = 6f;
|
||||
public static float minAngle = -15f;
|
||||
public static float maxAngle = 15f;
|
||||
|
||||
public static float despawnTime = 10f;
|
||||
|
||||
public void CreateProp(GameObject target, Vector3 direction){
|
||||
gameObject.layer = 6;
|
||||
|
||||
transform.position = target.transform.position;
|
||||
transform.rotation = target.transform.rotation;
|
||||
transform.localScale = target.transform.lossyScale * 0.9f; // so they don't get stuck in any frame
|
||||
|
||||
var targetMesh = target.GetComponent<MeshFilter>().sharedMesh;
|
||||
meshFilter.sharedMesh = targetMesh;
|
||||
meshCollider.sharedMesh = targetMesh;
|
||||
meshRenderer.materials = target.GetComponent<MeshRenderer>().materials;
|
||||
|
||||
var randomDirection = Quaternion.Euler(Random.Range(-minAngle, maxAngle), Random.Range(-minAngle, maxAngle), Random.Range(-minAngle, maxAngle)) * direction;
|
||||
var force = randomDirection * Random.Range(minForce, maxForce);
|
||||
rigidbody.AddForce(force, ForceMode.Impulse);
|
||||
|
||||
StartCoroutine(DespawnTimer());
|
||||
}
|
||||
|
||||
IEnumerator DespawnTimer(){
|
||||
yield return new WaitForSeconds(despawnTime);
|
||||
gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ScarletMansion {
|
||||
public class ScarletVent : MonoBehaviour {
|
||||
|
||||
public AudioSource shakeAudioSource;
|
||||
public AudioSource summonAudioSource;
|
||||
public PlayAudioAnimationEvent audioEvent;
|
||||
|
||||
[Header("Shake")]
|
||||
public ParticleSystem spawningPartciles;
|
||||
public ParticleSystem lightingParticles;
|
||||
public ParticleSystem emitParticles;
|
||||
public float volumeToRate = 1f;
|
||||
|
||||
public static bool prewarm;
|
||||
|
||||
void Start(){
|
||||
if (!prewarm){
|
||||
OpenVentClientRpc();
|
||||
prewarm = true;
|
||||
Plugin.logger.LogInfo("Prewarming particles by forcing it emit now lmao");
|
||||
}
|
||||
}
|
||||
|
||||
private void PlayParticleSystem(ParticleSystem ps){
|
||||
if (ps.isPlaying) return;
|
||||
ps.Play();
|
||||
}
|
||||
|
||||
private void StopParticleSystem(ParticleSystem ps){
|
||||
if (!ps.isPlaying) return;
|
||||
ps.Stop();
|
||||
}
|
||||
|
||||
public void OpenVentClientRpc(){
|
||||
emitParticles.Play();
|
||||
audioEvent.PlayAudio1Oneshot();
|
||||
}
|
||||
|
||||
void Update(){
|
||||
var isPlaying = shakeAudioSource.isPlaying;
|
||||
if (isPlaying){
|
||||
PlayParticleSystem(spawningPartciles);
|
||||
SetEmissionRate(spawningPartciles, shakeAudioSource.volume * volumeToRate);
|
||||
|
||||
if (shakeAudioSource.volume >= 0.8f) PlayParticleSystem(lightingParticles);
|
||||
else StopParticleSystem(lightingParticles);
|
||||
} else {
|
||||
StopParticleSystem(spawningPartciles);
|
||||
StopParticleSystem(lightingParticles);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetEmissionRate(ParticleSystem ps, float mult){
|
||||
var emis = ps.emission;
|
||||
emis.rateOverTimeMultiplier = mult;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue