using System; using System.Collections.Generic; using System.Linq; using Assets.CoreScripts; using Hazel; using InnerNet; using PowerTools; using UnityEngine; //c 场景中的物件,包含门的开启等,在这里同步 // 这个结构由host玩家管理,所有者是host玩家,类似GameData 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 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 { 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; } } public ShipStatus() { //c 所有的systems this.Systems = new Dictionary(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(); this.AllConsoles = base.GetComponentsInChildren(); this.AllVents = base.GetComponentsInChildren(); this.AssignTaskIndexes(); ShipStatus.Instance = this; } public void Start() { Camera.main.backgroundColor = this.CameraColor; if (DestroyableSingleton.InstanceExists) { DestroyableSingleton.Instance.Chat.ForceClosed(); DestroyableSingleton.Instance.Chat.SetVisible(false); DestroyableSingleton.Instance.GameSettings.gameObject.SetActive(false); } DeconSystem componentInChildren = base.GetComponentInChildren(); 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 (Vector2)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((string)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((string)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 list = (from pcd in GameData.Instance.AllPlayers where !pcd.Disconnected select pcd into pc where !pc.IsDead select pc).ToList(); int adjustedNumImpostors = PlayerControl.GameOptions.GetAdjustedNumImpostors(GameData.Instance.PlayerCount); list.RemoveDupes(); 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.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 allPlayers = GameData.Instance.AllPlayers; HashSet hashSet = new HashSet(); List list = new List(10); List list2 = this.CommonTasks.ToList(); list2.Shuffle(); 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(); list.Add((byte)list2[index].Index); list2.RemoveAt(index); } List list3 = this.LongTasks.ToList(); list3.Shuffle(); List list4 = this.NormalTasks.ToList(); list4.Shuffle(); 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().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 tasks, HashSet usedTaskTypes, List unusedTasks) { int num = 0; int num2 = 0; Func <>9__0; while (num2 < count && num++ != 1000) { if (start >= unusedTasks.Count) { start = 0; unusedTasks.Shuffle(); Func 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) //c 只有host检查是否结束游戏,然后广播给其他玩家 { 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.InstanceExists || num3 > 0)) { if (!DestroyableSingleton.InstanceExists) { base.enabled = false; ShipStatus.RpcEndGame((TempData.LastDeathReason == DeathReason.Disconnect) ? GameOverReason.ImpostorDisconnect : GameOverReason.HumansByVote, !SaveManager.BoughtNoAds); return; } DestroyableSingleton.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.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.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.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.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.InstanceExists) { base.enabled = false; ShipStatus.RpcEndGame(GameOverReason.ImpostorBySabotage, !SaveManager.BoughtNoAds); return; } DestroyableSingleton.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.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().ForEach(delegate(DeadBody b) { UnityEngine.Object.Destroy(b.gameObject); }); } public bool CheckTaskCompletion() { if (DestroyableSingleton.InstanceExists) { if (PlayerControl.LocalPlayer.myTasks.All((PlayerTask t) => t.IsComplete)) { DestroyableSingleton.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; } private enum RpcCalls { CloseDoorsOfType, RepairSystem } // 关门 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(), reader.ReadByte()); } }