diff options
Diffstat (limited to 'Client/Assembly-CSharp/ShipStatus.cs')
-rw-r--r-- | Client/Assembly-CSharp/ShipStatus.cs | 738 |
1 files changed, 738 insertions, 0 deletions
diff --git a/Client/Assembly-CSharp/ShipStatus.cs b/Client/Assembly-CSharp/ShipStatus.cs new file mode 100644 index 0000000..81d8b4a --- /dev/null +++ b/Client/Assembly-CSharp/ShipStatus.cs @@ -0,0 +1,738 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Assets.CoreScripts; +using Hazel; +using InnerNet; +using PowerTools; +using UnityEngine; + +//场景中的物件,包含门的开启等,在这里同步 +public class ShipStatus : InnerNetObject +{ + public ShipRoom[] AllRooms { get; private set; } + + public Vent[] AllVents { get; private set; } + + public static ShipStatus Instance; + + public Color CameraColor = Color.black; + + public float MaxLightRadius = 100f; + + public float MinLightRadius; + + public float MapScale = 4.4f; + + public Vector2 MapOffset = new Vector2(0.54f, 1.25f); + + public MapBehaviour MapPrefab; + + public Transform SpawnCenter; + + public float SpawnRadius = 1.55f; + + public AudioClip shipHum; + + public NormalPlayerTask[] CommonTasks; + + public NormalPlayerTask[] LongTasks; + + public NormalPlayerTask[] NormalTasks; + + public PlayerTask[] SpecialTasks; + + public AutoOpenDoor[] AllDoors; + + public global::Console[] AllConsoles; + + //c 场景中的门、反应堆等物件的状态 + public Dictionary<SystemTypes, ISystemType> Systems; + + public AnimationClip[] WeaponFires; + + public SpriteAnim WeaponsImage; + + public AnimationClip HatchActive; + + public SpriteAnim Hatch; + + public ParticleSystem HatchParticles; + + public AnimationClip ShieldsActive; + + public SpriteAnim[] ShieldsImages; + + public SpriteRenderer ShieldBorder; + + public Sprite ShieldBorderOn; + + public SpriteRenderer MedScanner; + + private int WeaponFireIdx; + + public float Timer; + + public float EmergencyCooldown; + + private RaycastHit2D[] volumeBuffer = new RaycastHit2D[5]; + + public class SystemTypeComparer : IEqualityComparer<SystemTypes> + { + public static readonly ShipStatus.SystemTypeComparer Instance = new ShipStatus.SystemTypeComparer(); + + public bool Equals(SystemTypes x, SystemTypes y) + { + return x == y; + } + + public int GetHashCode(SystemTypes obj) + { + return (int)obj; + } + } + + private enum RpcCalls + { + CloseDoorsOfType, + RepairSystem + } + + public ShipStatus() + { + //c 所有的systems + this.Systems = new Dictionary<SystemTypes, ISystemType>(ShipStatus.SystemTypeComparer.Instance) + { + { + SystemTypes.Electrical, + new SwitchSystem() + }, + { + SystemTypes.MedBay, + new MedScanSystem() + }, + { + SystemTypes.Reactor, + new ReactorSystemType() + }, + { + SystemTypes.LifeSupp, + new LifeSuppSystemType() + }, + { + SystemTypes.Security, + new SecurityCameraSystemType() + }, + { + SystemTypes.Comms, + new HudOverrideSystemType() + }, + { + SystemTypes.Doors, + new DoorsSystemType() + } + }; + this.Systems.Add(SystemTypes.Sabotage, new SabotageSystemType(new IActivatable[] + { + (IActivatable)this.Systems[SystemTypes.Comms], + (IActivatable)this.Systems[SystemTypes.Reactor], + (IActivatable)this.Systems[SystemTypes.LifeSupp], + (IActivatable)this.Systems[SystemTypes.Electrical] + })); + } + + private void Awake() + { + this.AllRooms = base.GetComponentsInChildren<ShipRoom>(); + this.AllConsoles = base.GetComponentsInChildren<global::Console>(); + this.AllVents = base.GetComponentsInChildren<Vent>(); + this.AssignTaskIndexes(); + ShipStatus.Instance = this; + } + + public void Start() + { + Camera.main.backgroundColor = this.CameraColor; + if (DestroyableSingleton<HudManager>.InstanceExists) + { + DestroyableSingleton<HudManager>.Instance.Chat.ForceClosed(); + DestroyableSingleton<HudManager>.Instance.Chat.SetVisible(false); + DestroyableSingleton<HudManager>.Instance.GameSettings.gameObject.SetActive(false); + } + DeconSystem componentInChildren = base.GetComponentInChildren<DeconSystem>(); + if (componentInChildren) + { + this.Systems.Add(SystemTypes.Decontamination, componentInChildren); + } + SoundManager.Instance.StopAllSound(); + AudioSource audioSource = SoundManager.Instance.PlaySound(this.shipHum, true, 1f); + if (audioSource) + { + audioSource.pitch = 0.8f; + } + if (Constants.ShouldPlaySfx()) + { + for (int i = 0; i < this.AllRooms.Length; i++) + { + ShipRoom room = this.AllRooms[i]; + if (room.AmbientSound) + { + SoundManager.Instance.PlayDynamicSound("Amb " + room.RoomId, room.AmbientSound, true, delegate(AudioSource player, float dt) + { + this.GetAmbientSoundVolume(room, player, dt); + }, false); + } + } + } + } + + public override void OnDestroy() + { + SoundManager.Instance.StopAllSound(); + base.OnDestroy(); + } + + public Vector2 GetSpawnLocation(int playerId, int numPlayer) + { + Vector2 vector = Vector2.up; + vector = vector.Rotate((float)(playerId - 1) * (360f / (float)numPlayer)); + vector *= this.SpawnRadius; + return this.SpawnCenter.position + vector + new Vector2(0f, 0.3636f); + } + + public void StartShields() + { + for (int i = 0; i < this.ShieldsImages.Length; i++) + { + this.ShieldsImages[i].Play(this.ShieldsActive, 1f); + } + this.ShieldBorder.sprite = this.ShieldBorderOn; + } + + public void FireWeapon() + { + if (!this.WeaponsImage.IsPlaying(null)) + { + this.WeaponsImage.Play(this.WeaponFires[this.WeaponFireIdx], 1f); + this.WeaponFireIdx = (this.WeaponFireIdx + 1) % 2; + } + } + + public NormalPlayerTask GetTaskById(byte idx) + { + NormalPlayerTask result; + if ((result = this.CommonTasks.FirstOrDefault((NormalPlayerTask t) => t.Index == (int)idx)) == null) + { + result = (this.LongTasks.FirstOrDefault((NormalPlayerTask t) => t.Index == (int)idx) ?? this.NormalTasks.FirstOrDefault((NormalPlayerTask t) => t.Index == (int)idx)); + } + return result; + } + + public void OpenHatch() + { + if (!this.Hatch.IsPlaying(null)) + { + this.Hatch.Play(this.HatchActive, 1f); + this.HatchParticles.Play(); + } + } + + public void CloseDoorsOfType(SystemTypes room) + { + (this.Systems[SystemTypes.Doors] as DoorsSystemType).CloseDoorsOfType(room); + base.SetDirtyBit(65536U); + } + + public void RepairSystem(SystemTypes systemType, PlayerControl player, byte amount) + { + this.Systems[systemType].RepairDamage(player, amount); + base.SetDirtyBit(1U << (int)systemType); + } + + internal void SelectInfected() + { + List<GameData.PlayerInfo> list = (from pcd in GameData.Instance.AllPlayers + where !pcd.Disconnected + select pcd into pc + where !pc.IsDead + select pc).ToList<GameData.PlayerInfo>(); + int adjustedNumImpostors = PlayerControl.GameOptions.GetAdjustedNumImpostors(GameData.Instance.PlayerCount); + list.RemoveDupes<GameData.PlayerInfo>(); + GameData.PlayerInfo[] array = new GameData.PlayerInfo[Mathf.Min(list.Count, adjustedNumImpostors)]; + for (int i = 0; i < array.Length; i++) + { + int index = HashRandom.FastNext(list.Count); + array[i] = list[index]; + list.RemoveAt(index); + } + foreach (GameData.PlayerInfo playerInfo in array) + { + DestroyableSingleton<Telemetry>.Instance.SelectInfected((int)playerInfo.ColorId, playerInfo.HatId); + } + PlayerControl.LocalPlayer.RpcSetInfected(array); + } + + private void AssignTaskIndexes() + { + int num = 0; + for (int i = 0; i < this.CommonTasks.Length; i++) + { + this.CommonTasks[i].Index = num++; + } + for (int j = 0; j < this.LongTasks.Length; j++) + { + this.LongTasks[j].Index = num++; + } + for (int k = 0; k < this.NormalTasks.Length; k++) + { + this.NormalTasks[k].Index = num++; + } + } + + public void Begin() + { + this.AssignTaskIndexes(); + GameOptionsData gameOptions = PlayerControl.GameOptions; + List<GameData.PlayerInfo> allPlayers = GameData.Instance.AllPlayers; + HashSet<TaskTypes> hashSet = new HashSet<TaskTypes>(); + List<byte> list = new List<byte>(10); + List<NormalPlayerTask> list2 = this.CommonTasks.ToList<NormalPlayerTask>(); + list2.Shuffle<NormalPlayerTask>(); + int num = 0; + this.AddTasksFromList(ref num, gameOptions.NumCommonTasks, list, hashSet, list2); + for (int i = 0; i < gameOptions.NumCommonTasks; i++) + { + if (list2.Count == 0) + { + Debug.LogWarning("Not enough common tasks"); + break; + } + int index = list2.RandomIdx<NormalPlayerTask>(); + list.Add((byte)list2[index].Index); + list2.RemoveAt(index); + } + List<NormalPlayerTask> list3 = this.LongTasks.ToList<NormalPlayerTask>(); + list3.Shuffle<NormalPlayerTask>(); + List<NormalPlayerTask> list4 = this.NormalTasks.ToList<NormalPlayerTask>(); + list4.Shuffle<NormalPlayerTask>(); + int num2 = 0; + int num3 = 0; + int count = gameOptions.NumShortTasks; + if (gameOptions.NumCommonTasks + gameOptions.NumLongTasks + gameOptions.NumShortTasks == 0) + { + count = 1; + } + byte b = 0; + while ((int)b < allPlayers.Count) + { + hashSet.Clear(); + list.RemoveRange(gameOptions.NumCommonTasks, list.Count - gameOptions.NumCommonTasks); + this.AddTasksFromList(ref num2, gameOptions.NumLongTasks, list, hashSet, list3); + this.AddTasksFromList(ref num3, count, list, hashSet, list4); + GameData.PlayerInfo playerInfo = allPlayers[(int)b]; + if (playerInfo.Object && !playerInfo.Object.GetComponent<DummyBehaviour>().enabled) + { + byte[] taskTypeIds = list.ToArray(); + GameData.Instance.RpcSetTasks(playerInfo.PlayerId, taskTypeIds); + } + b += 1; + } + base.enabled = true; + } + + private void AddTasksFromList(ref int start, int count, List<byte> tasks, HashSet<TaskTypes> usedTaskTypes, List<NormalPlayerTask> unusedTasks) + { + int num = 0; + int num2 = 0; + Func<NormalPlayerTask, bool> <>9__0; + while (num2 < count && num++ != 1000) + { + if (start >= unusedTasks.Count) + { + start = 0; + unusedTasks.Shuffle<NormalPlayerTask>(); + Func<NormalPlayerTask, bool> predicate; + if ((predicate = <>9__0) == null) + { + predicate = (<>9__0 = ((NormalPlayerTask t) => usedTaskTypes.Contains(t.TaskType))); + } + if (unusedTasks.All(predicate)) + { + Debug.Log("Not enough task types"); + usedTaskTypes.Clear(); + } + } + int num3 = start; + start = num3 + 1; + NormalPlayerTask normalPlayerTask = unusedTasks[num3]; + if (!usedTaskTypes.Add(normalPlayerTask.TaskType)) + { + num2--; + } + else + { + tasks.Add((byte)normalPlayerTask.Index); + } + num2++; + } + } + + public void FixedUpdate() + { + if (!AmongUsClient.Instance) + { + return; + } + this.Timer += Time.fixedDeltaTime; + this.EmergencyCooldown -= Time.fixedDeltaTime; + if (GameData.Instance) + { + GameData.Instance.RecomputeTaskCounts(); + } + if (AmongUsClient.Instance.AmHost) + { + this.CheckEndCriteria(); + } + if (AmongUsClient.Instance.AmClient) + { + for (int i = 0; i < SystemTypeHelpers.AllTypes.Length; i++) + { + SystemTypes systemTypes = SystemTypeHelpers.AllTypes[i]; + ISystemType systemType; + if (this.Systems.TryGetValue(systemTypes, out systemType) && systemType.Detoriorate(Time.fixedDeltaTime)) + { + base.SetDirtyBit(1U << (int)systemTypes); + } + } + } + } + + private void GetAmbientSoundVolume(ShipRoom room, AudioSource player, float dt) + { + if (!PlayerControl.LocalPlayer) + { + player.volume = 0f; + return; + } + Vector2 vector = room.transform.position; + Vector2 truePosition = PlayerControl.LocalPlayer.GetTruePosition(); + float num = Vector2.Distance(vector, truePosition); + if (num > 8f) + { + player.volume = 0f; + return; + } + Vector2 direction = truePosition - vector; + int num2 = Physics2D.RaycastNonAlloc(vector, direction, this.volumeBuffer, num, Constants.ShipOnlyMask); + float num3 = 1f - num / 8f - (float)num2 * 0.25f; + player.volume = Mathf.Lerp(player.volume, num3 * 0.7f, dt); + } + + public float CalculateLightRadius(GameData.PlayerInfo player) + { + if (player.IsDead) + { + return this.MaxLightRadius; + } + SwitchSystem switchSystem = (SwitchSystem)this.Systems[SystemTypes.Electrical]; + if (player.IsImpostor) + { + return this.MaxLightRadius * PlayerControl.GameOptions.ImpostorLightMod; + } + float t = (float)switchSystem.Value / 255f; + return Mathf.Lerp(this.MinLightRadius, this.MaxLightRadius, t) * PlayerControl.GameOptions.CrewLightMod; + } + + //c 序列化所有物件的状态 + public override bool Serialize(MessageWriter writer, bool initialState) + { + if (initialState) + { + (this.Systems[SystemTypes.Doors] as DoorsSystemType).SetDoors(this.AllDoors); + short num = 0; + while ((int)num < SystemTypeHelpers.AllTypes.Length) + { + SystemTypes key = SystemTypeHelpers.AllTypes[(int)num]; + ISystemType systemType; + if (this.Systems.TryGetValue(key, out systemType)) + { + systemType.Serialize(writer, true); + } + num += 1; + } + return true; + } + if (this.DirtyBits != 0U) + { + writer.WritePacked(this.DirtyBits); + short num2 = 0; + while ((int)num2 < SystemTypeHelpers.AllTypes.Length) + { + SystemTypes systemTypes = SystemTypeHelpers.AllTypes[(int)num2]; + ISystemType systemType2; + if (((ulong)this.DirtyBits & (ulong)(1L << (int)(systemTypes & (SystemTypes)31))) != 0UL && this.Systems.TryGetValue(systemTypes, out systemType2)) + { + systemType2.Serialize(writer, false); + } + num2 += 1; + } + this.DirtyBits = 0U; + return true; + } + return false; + } + + public override void Deserialize(MessageReader reader, bool initialState) + { + if (initialState) + { + (this.Systems[SystemTypes.Doors] as DoorsSystemType).SetDoors(this.AllDoors); + short num = 0; + while ((int)num < SystemTypeHelpers.AllTypes.Length) + { + SystemTypes key = (SystemTypes)num; + ISystemType systemType; + if (this.Systems.TryGetValue(key, out systemType)) + { + systemType.Deserialize(reader, true); + } + num += 1; + } + return; + } + uint num2 = reader.ReadPackedUInt32(); + short num3 = 0; + while ((int)num3 < SystemTypeHelpers.AllTypes.Length) + { + SystemTypes systemTypes = SystemTypeHelpers.AllTypes[(int)num3]; + ISystemType systemType2; + if (((ulong)num2 & (ulong)(1L << (int)(systemTypes & (SystemTypes)31))) != 0UL && this.Systems.TryGetValue(systemTypes, out systemType2)) + { + systemType2.Deserialize(reader, false); + } + num3 += 1; + } + } + + private void CheckEndCriteria() + { + if (!GameData.Instance) + { + return; + } + LifeSuppSystemType lifeSuppSystemType = (LifeSuppSystemType)this.Systems[SystemTypes.LifeSupp]; + if (lifeSuppSystemType.Countdown < 0f) + { + this.EndGameForSabotage(); + lifeSuppSystemType.Countdown = 10000f; + } + ReactorSystemType reactorSystemType = (ReactorSystemType)this.Systems[SystemTypes.Reactor]; + if (reactorSystemType.Countdown < 0f) + { + this.EndGameForSabotage(); + reactorSystemType.Countdown = 10000f; + } + int num = 0; + int num2 = 0; + int num3 = 0; + for (int i = 0; i < GameData.Instance.PlayerCount; i++) + { + GameData.PlayerInfo playerInfo = GameData.Instance.AllPlayers[i]; + if (!playerInfo.Disconnected) + { + if (playerInfo.IsImpostor) + { + num3++; + } + if (!playerInfo.IsDead) + { + if (playerInfo.IsImpostor) + { + num2++; + } + else + { + num++; + } + } + } + } + if (num2 <= 0 && (!DestroyableSingleton<TutorialManager>.InstanceExists || num3 > 0)) + { + if (!DestroyableSingleton<TutorialManager>.InstanceExists) + { + base.enabled = false; + ShipStatus.RpcEndGame((TempData.LastDeathReason == DeathReason.Disconnect) ? GameOverReason.ImpostorDisconnect : GameOverReason.HumansByVote, !SaveManager.BoughtNoAds); + return; + } + DestroyableSingleton<HudManager>.Instance.ShowPopUp("Normally The Crew would have just won because The Impostor is dead. For free play, we revive everyone instead."); + ShipStatus.ReviveEveryone(); + return; + } + else + { + if (num > num2) + { + if (!DestroyableSingleton<TutorialManager>.InstanceExists) + { + if (GameData.Instance.TotalTasks <= GameData.Instance.CompletedTasks) + { + base.enabled = false; + ShipStatus.RpcEndGame(GameOverReason.HumansByTask, !SaveManager.BoughtNoAds); + return; + } + } + else if (PlayerControl.LocalPlayer.myTasks.All((PlayerTask t) => t.IsComplete)) + { + DestroyableSingleton<HudManager>.Instance.ShowPopUp("Normally The Crew would have just won because the task bar is full. For free play, we issue new tasks instead."); + this.Begin(); + } + return; + } + if (!DestroyableSingleton<TutorialManager>.InstanceExists) + { + base.enabled = false; + GameOverReason endReason; + switch (TempData.LastDeathReason) + { + case DeathReason.Exile: + endReason = GameOverReason.ImpostorByVote; + break; + case DeathReason.Kill: + endReason = GameOverReason.ImpostorByKill; + break; + default: + endReason = GameOverReason.HumansDisconnect; + break; + } + ShipStatus.RpcEndGame(endReason, !SaveManager.BoughtNoAds); + return; + } + DestroyableSingleton<HudManager>.Instance.ShowPopUp("Normally The Impostor would have just won because The Crew can no longer win. For free play, we revive everyone instead."); + ShipStatus.ReviveEveryone(); + return; + } + } + + private void EndGameForSabotage() + { + if (!DestroyableSingleton<TutorialManager>.InstanceExists) + { + base.enabled = false; + ShipStatus.RpcEndGame(GameOverReason.ImpostorBySabotage, !SaveManager.BoughtNoAds); + return; + } + DestroyableSingleton<HudManager>.Instance.ShowPopUp("Normally The Impostor would have just won because of the critical sabotage. Instead we just shut it off."); + } + + public bool IsGameOverDueToDeath() + { + int num = 0; + int num2 = 0; + int num3 = 0; + for (int i = 0; i < GameData.Instance.PlayerCount; i++) + { + GameData.PlayerInfo playerInfo = GameData.Instance.AllPlayers[i]; + if (!playerInfo.Disconnected) + { + if (playerInfo.IsImpostor) + { + num3++; + } + if (!playerInfo.IsDead) + { + if (playerInfo.IsImpostor) + { + num2++; + } + else + { + num++; + } + } + } + } + return (num2 <= 0 && (!DestroyableSingleton<TutorialManager>.InstanceExists || num3 > 0)) || num <= num2; + } + + private static void RpcEndGame(GameOverReason endReason, bool showAd) + { + MessageWriter messageWriter = AmongUsClient.Instance.StartEndGame(); + messageWriter.Write((byte)endReason); + messageWriter.Write(showAd); + AmongUsClient.Instance.FinishEndGame(messageWriter); + } + + private static void ReviveEveryone() + { + for (int i = 0; i < GameData.Instance.PlayerCount; i++) + { + GameData.Instance.AllPlayers[i].Object.Revive(); + } + UnityEngine.Object.FindObjectsOfType<DeadBody>().ForEach(delegate(DeadBody b) + { + UnityEngine.Object.Destroy(b.gameObject); + }); + } + + public bool CheckTaskCompletion() + { + if (DestroyableSingleton<TutorialManager>.InstanceExists) + { + if (PlayerControl.LocalPlayer.myTasks.All((PlayerTask t) => t.IsComplete)) + { + DestroyableSingleton<HudManager>.Instance.ShowPopUp("Normally The Crew would have just won because the task bar is full. For free play, we issue new tasks instead."); + this.Begin(); + } + return false; + } + GameData.Instance.RecomputeTaskCounts(); + if (GameData.Instance.TotalTasks <= GameData.Instance.CompletedTasks) + { + base.enabled = false; + ShipStatus.RpcEndGame(GameOverReason.HumansByTask, !SaveManager.BoughtNoAds); + return true; + } + return false; + } + + public void RpcCloseDoorsOfType(SystemTypes type) + { + if (AmongUsClient.Instance.AmHost) + { + this.CloseDoorsOfType(type); + return; + } + MessageWriter messageWriter = AmongUsClient.Instance.StartRpcImmediately(this.NetId, 0, SendOption.Reliable, AmongUsClient.Instance.HostId); + messageWriter.Write((byte)type); + AmongUsClient.Instance.FinishRpcImmediately(messageWriter); + } + + public void RpcRepairSystem(SystemTypes systemType, int amount) + { + if (AmongUsClient.Instance.AmHost) + { + this.RepairSystem(systemType, PlayerControl.LocalPlayer, (byte)amount); + return; + } + MessageWriter messageWriter = AmongUsClient.Instance.StartRpcImmediately(this.NetId, 1, SendOption.Reliable, AmongUsClient.Instance.HostId); + messageWriter.Write((byte)systemType); + messageWriter.WriteNetObject(PlayerControl.LocalPlayer); + messageWriter.Write((byte)amount); + AmongUsClient.Instance.FinishRpcImmediately(messageWriter); + } + + public override void HandleRpc(byte callId, MessageReader reader) + { + if (callId == 0) + { + this.CloseDoorsOfType((SystemTypes)reader.ReadByte()); + return; + } + if (callId != 1) + { + return; + } + this.RepairSystem((SystemTypes)reader.ReadByte(), reader.ReadNetObject<PlayerControl>(), reader.ReadByte()); + } +} |