mirror of
https://github.com/Gurge44/EndlessHostRoles.git
synced 2026-10-20 01:46:25 +00:00
451 lines
21 KiB
C#
451 lines
21 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Linq;
|
|
using AmongUs.GameOptions;
|
|
using EHR.Modules;
|
|
using HarmonyLib;
|
|
using Hazel;
|
|
using UnityEngine;
|
|
|
|
namespace EHR
|
|
{
|
|
public static class RoomRush
|
|
{
|
|
private static OptionItem GlobalTimeMultiplier;
|
|
private static OptionItem TimeWhenFirstPlayerEntersRoom;
|
|
private static OptionItem VentTimes;
|
|
private static OptionItem DisplayRoomName;
|
|
private static OptionItem DisplayArrowToRoom;
|
|
|
|
public static readonly HashSet<string> HasPlayedFriendCodes = [];
|
|
|
|
public static Dictionary<byte, int> VentLimit = [];
|
|
|
|
private static HashSet<SystemTypes> AllRooms = [];
|
|
private static SystemTypes RoomGoal;
|
|
private static int TimeLeft;
|
|
private static HashSet<byte> DonePlayers = [];
|
|
|
|
public static bool GameGoing;
|
|
private static DateTime GameStartDateTime;
|
|
|
|
private static RandomSpawn.SpawnMap Map;
|
|
|
|
private static readonly Dictionary<MapNames, Dictionary<(SystemTypes, SystemTypes), int>> Multipliers = new()
|
|
{
|
|
[MapNames.Skeld] = new()
|
|
{
|
|
[(SystemTypes.Admin, SystemTypes.Nav)] = 2,
|
|
[(SystemTypes.Admin, SystemTypes.Comms)] = 2,
|
|
[(SystemTypes.Admin, SystemTypes.Shields)] = 3,
|
|
[(SystemTypes.Admin, SystemTypes.LifeSupp)] = 4,
|
|
[(SystemTypes.Electrical, SystemTypes.MedBay)] = 3,
|
|
[(SystemTypes.Electrical, SystemTypes.Security)] = 3,
|
|
[(SystemTypes.MedBay, SystemTypes.Security)] = 3,
|
|
[(SystemTypes.Admin, SystemTypes.Security)] = 2,
|
|
[(SystemTypes.Storage, SystemTypes.Security)] = 2,
|
|
[(SystemTypes.Storage, SystemTypes.MedBay)] = 2
|
|
},
|
|
[MapNames.Mira] = new()
|
|
{
|
|
[(SystemTypes.Launchpad, SystemTypes.Reactor)] = 2,
|
|
[(SystemTypes.Greenhouse, SystemTypes.Laboratory)] = 2,
|
|
[(SystemTypes.Office, SystemTypes.Laboratory)] = 2,
|
|
[(SystemTypes.Storage, SystemTypes.Comms)] = 5,
|
|
[(SystemTypes.Cafeteria, SystemTypes.Comms)] = 3,
|
|
[(SystemTypes.Balcony, SystemTypes.Comms)] = 2,
|
|
[(SystemTypes.Storage, SystemTypes.MedBay)] = 4,
|
|
[(SystemTypes.Cafeteria, SystemTypes.MedBay)] = 3,
|
|
[(SystemTypes.Balcony, SystemTypes.MedBay)] = 5,
|
|
[(SystemTypes.Storage, SystemTypes.LockerRoom)] = 2,
|
|
[(SystemTypes.Balcony, SystemTypes.LockerRoom)] = 2,
|
|
[(SystemTypes.Launchpad, SystemTypes.Storage)] = 2
|
|
},
|
|
[MapNames.Polus] = new()
|
|
{
|
|
[(SystemTypes.Laboratory, SystemTypes.Admin)] = 2,
|
|
[(SystemTypes.Storage, SystemTypes.Comms)] = 2,
|
|
[(SystemTypes.Storage, SystemTypes.Office)] = 2,
|
|
[(SystemTypes.Storage, SystemTypes.Admin)] = 2,
|
|
[(SystemTypes.Security, SystemTypes.LifeSupp)] = 2,
|
|
[(SystemTypes.Security, SystemTypes.Comms)] = 2,
|
|
[(SystemTypes.Security, SystemTypes.Electrical)] = 2,
|
|
[(SystemTypes.Comms, SystemTypes.Electrical)] = 2
|
|
},
|
|
[MapNames.Airship] = new()
|
|
{
|
|
[(SystemTypes.MainHall, SystemTypes.GapRoom)] = 2,
|
|
[(SystemTypes.MainHall, SystemTypes.Kitchen)] = 2,
|
|
[(SystemTypes.Showers, SystemTypes.CargoBay)] = 2,
|
|
[(SystemTypes.Showers, SystemTypes.Lounge)] = 2,
|
|
[(SystemTypes.Showers, SystemTypes.Electrical)] = 2,
|
|
[(SystemTypes.Showers, SystemTypes.Medical)] = 2,
|
|
[(SystemTypes.Ventilation, SystemTypes.CargoBay)] = 2,
|
|
[(SystemTypes.Ventilation, SystemTypes.Lounge)] = 2,
|
|
[(SystemTypes.Ventilation, SystemTypes.Electrical)] = 2,
|
|
[(SystemTypes.Ventilation, SystemTypes.Medical)] = 2,
|
|
[(SystemTypes.Comms, SystemTypes.VaultRoom)] = 2,
|
|
[(SystemTypes.GapRoom, SystemTypes.Records)] = 3,
|
|
[(SystemTypes.GapRoom, SystemTypes.Lounge)] = 3,
|
|
[(SystemTypes.GapRoom, SystemTypes.Brig)] = 4,
|
|
[(SystemTypes.GapRoom, SystemTypes.VaultRoom)] = 3,
|
|
[(SystemTypes.GapRoom, SystemTypes.Engine)] = 2,
|
|
[(SystemTypes.MeetingRoom, SystemTypes.Records)] = 3,
|
|
[(SystemTypes.MeetingRoom, SystemTypes.Lounge)] = 3,
|
|
[(SystemTypes.MeetingRoom, SystemTypes.MainHall)] = 2,
|
|
[(SystemTypes.Engine, SystemTypes.Security)] = 2,
|
|
[(SystemTypes.MainHall, SystemTypes.Security)] = 2
|
|
},
|
|
[MapNames.Fungle] = new()
|
|
{
|
|
[(SystemTypes.Lookout, SystemTypes.SleepingQuarters)] = 3,
|
|
[(SystemTypes.Lookout, SystemTypes.MeetingRoom)] = 2,
|
|
[(SystemTypes.Lookout, SystemTypes.Storage)] = 2,
|
|
[(SystemTypes.Lookout, SystemTypes.Dropship)] = 2,
|
|
[(SystemTypes.Lookout, SystemTypes.FishingDock)] = 2,
|
|
[(SystemTypes.Lookout, SystemTypes.RecRoom)] = 2,
|
|
[(SystemTypes.Lookout, SystemTypes.Kitchen)] = 2,
|
|
[(SystemTypes.Lookout, SystemTypes.Cafeteria)] = 2,
|
|
[(SystemTypes.MiningPit, SystemTypes.SleepingQuarters)] = 3,
|
|
[(SystemTypes.MiningPit, SystemTypes.MeetingRoom)] = 2,
|
|
[(SystemTypes.MiningPit, SystemTypes.Storage)] = 2,
|
|
[(SystemTypes.MiningPit, SystemTypes.Dropship)] = 2,
|
|
[(SystemTypes.MiningPit, SystemTypes.FishingDock)] = 2,
|
|
[(SystemTypes.MiningPit, SystemTypes.RecRoom)] = 2,
|
|
[(SystemTypes.MiningPit, SystemTypes.Kitchen)] = 2,
|
|
[(SystemTypes.MiningPit, SystemTypes.Cafeteria)] = 2
|
|
}
|
|
};
|
|
|
|
public static void SetupCustomOption()
|
|
{
|
|
var id = 69_217_001;
|
|
Color color = Utils.GetRoleColor(CustomRoles.RRPlayer);
|
|
const CustomGameMode gameMode = CustomGameMode.RoomRush;
|
|
|
|
GlobalTimeMultiplier = new FloatOptionItem(id++, "RR_GlobalTimeMultiplier", new(0.05f, 2f, 0.05f), 1f, TabGroup.GameSettings)
|
|
.SetHeader(true)
|
|
.SetColor(color)
|
|
.SetGameMode(gameMode);
|
|
|
|
TimeWhenFirstPlayerEntersRoom = new IntegerOptionItem(id++, "RR_TimeWhenTwoPlayersEntersRoom", new(1, 30, 1), 5, TabGroup.GameSettings)
|
|
.SetColor(color)
|
|
.SetGameMode(gameMode)
|
|
.SetValueFormat(OptionFormat.Seconds);
|
|
|
|
VentTimes = new IntegerOptionItem(id++, "RR_VentTimes", new(0, 90, 1), 1, TabGroup.GameSettings)
|
|
.SetColor(color)
|
|
.SetGameMode(gameMode)
|
|
.SetValueFormat(OptionFormat.Times);
|
|
|
|
DisplayRoomName = new BooleanOptionItem(id++, "RR_DisplayRoomName", true, TabGroup.GameSettings)
|
|
.SetColor(color)
|
|
.SetGameMode(gameMode);
|
|
|
|
DisplayArrowToRoom = new BooleanOptionItem(id, "RR_DisplayArrowToRoom", false, TabGroup.GameSettings)
|
|
.SetColor(color)
|
|
.SetGameMode(gameMode);
|
|
}
|
|
|
|
public static int GetSurvivalTime(byte id)
|
|
{
|
|
if (!Main.PlayerStates.TryGetValue(id, out PlayerState state)) return -1;
|
|
|
|
if (!state.IsDead) return 0;
|
|
|
|
DateTime died = state.RealKiller.TimeStamp;
|
|
TimeSpan time = died - GameStartDateTime;
|
|
return (int)time.TotalSeconds;
|
|
}
|
|
|
|
public static void OnGameStart()
|
|
{
|
|
if (!CustomGameMode.RoomRush.IsActiveOrIntegrated()) return;
|
|
|
|
Main.Instance.StartCoroutine(GameStartTasks());
|
|
}
|
|
|
|
private static IEnumerator GameStartTasks()
|
|
{
|
|
GameGoing = false;
|
|
|
|
int ventLimit = VentTimes.GetInt();
|
|
VentLimit = Main.AllPlayerControls.ToDictionary(x => x.PlayerId, _ => ventLimit);
|
|
|
|
AllRooms = ShipStatus.Instance.AllRooms.Select(x => x.RoomId).ToHashSet();
|
|
AllRooms.Remove(SystemTypes.Hallway);
|
|
AllRooms.Remove(SystemTypes.Outside);
|
|
AllRooms.RemoveWhere(x => x.ToString().Contains("Decontamination"));
|
|
|
|
DonePlayers = [];
|
|
|
|
Map = Main.CurrentMap switch
|
|
{
|
|
MapNames.Skeld => new RandomSpawn.SkeldSpawnMap(),
|
|
MapNames.Mira => new RandomSpawn.MiraHQSpawnMap(),
|
|
MapNames.Polus => new RandomSpawn.PolusSpawnMap(),
|
|
MapNames.Dleks => new RandomSpawn.DleksSpawnMap(),
|
|
MapNames.Airship => new RandomSpawn.AirshipSpawnMap(),
|
|
MapNames.Fungle => new RandomSpawn.FungleSpawnMap(),
|
|
_ => throw new ArgumentOutOfRangeException()
|
|
};
|
|
|
|
yield return new WaitForSeconds(Main.CurrentMap == MapNames.Airship ? 22f : 14f);
|
|
|
|
PlayerControl[] aapc = Main.AllAlivePlayerControls;
|
|
aapc.Do(x => x.RpcSetCustomRole(CustomRoles.RRPlayer));
|
|
|
|
if (Options.CurrentGameMode == CustomGameMode.AllInOne)
|
|
{
|
|
yield return new WaitForSeconds(4f);
|
|
goto Skip;
|
|
}
|
|
|
|
bool showTutorial = aapc.ExceptBy(HasPlayedFriendCodes, x => x.FriendCode).Count() >= aapc.Length / 3;
|
|
|
|
if (showTutorial)
|
|
{
|
|
string[] notifies = [Translator.GetString("RR_Tutorial_1"), Translator.GetString("RR_Tutorial_2"), Translator.GetString("RR_Tutorial_3"), Translator.GetString("RR_Tutorial_4")];
|
|
|
|
foreach (string notify in notifies)
|
|
{
|
|
aapc.Do(x => x.Notify(notify, 8f));
|
|
yield return new WaitForSeconds(3f);
|
|
}
|
|
|
|
yield return new WaitForSeconds(4f);
|
|
}
|
|
|
|
NameNotifyManager.Reset();
|
|
aapc.Do(x => x.Notify(Translator.GetString("RR_ReadyQM")));
|
|
|
|
yield return new WaitForSeconds(2f);
|
|
|
|
for (var i = 3; i > 0; i--)
|
|
{
|
|
int time = i;
|
|
NameNotifyManager.Reset();
|
|
aapc.Do(x => x.Notify(time.ToString()));
|
|
yield return new WaitForSeconds(1f);
|
|
}
|
|
|
|
Skip:
|
|
|
|
if (ventLimit > 0) aapc.Do(x => x.RpcChangeRoleBasis(CustomRoles.EngineerEHR));
|
|
|
|
Utils.SendRPC(CustomRPC.RoomRushDataSync, 1);
|
|
|
|
NameNotifyManager.Reset();
|
|
StartNewRound(true);
|
|
GameGoing = true;
|
|
GameStartDateTime = DateTime.Now;
|
|
}
|
|
|
|
private static void StartNewRound(bool initial = false)
|
|
{
|
|
if (GameStates.IsEnded) return;
|
|
|
|
SystemTypes previous = !initial
|
|
? RoomGoal
|
|
: Main.CurrentMap switch
|
|
{
|
|
MapNames.Skeld => SystemTypes.Cafeteria,
|
|
MapNames.Mira => SystemTypes.Launchpad,
|
|
MapNames.Dleks => SystemTypes.Cafeteria,
|
|
MapNames.Polus => SystemTypes.Dropship,
|
|
MapNames.Airship => SystemTypes.MainHall,
|
|
MapNames.Fungle => SystemTypes.Dropship,
|
|
_ => throw new ArgumentOutOfRangeException(Main.CurrentMap.ToString(), "Invalid map")
|
|
};
|
|
|
|
DonePlayers.Clear();
|
|
RoomGoal = AllRooms.Without(previous).RandomElement();
|
|
Vector2 goalPos = Map.Positions.GetValueOrDefault(RoomGoal, RoomGoal.GetRoomClass().transform.position);
|
|
Vector2 previousPos = Map.Positions.GetValueOrDefault(previous, initial ? Main.AllAlivePlayerControls.RandomElement().Pos() : previous.GetRoomClass().transform.position);
|
|
float distance = initial ? 50 : Vector2.Distance(goalPos, previousPos);
|
|
float speed = Main.RealOptionsData.GetFloat(FloatOptionNames.PlayerSpeedMod);
|
|
var time = (int)Math.Ceiling(distance / speed);
|
|
MapNames map = Main.CurrentMap;
|
|
Dictionary<(SystemTypes, SystemTypes), int> multipliers = Multipliers[map == MapNames.Dleks ? MapNames.Skeld : map];
|
|
time *= multipliers.GetValueOrDefault((previous, RoomGoal), multipliers.GetValueOrDefault((RoomGoal, previous), 1));
|
|
|
|
bool involvesDecontamination = Main.CurrentMap switch
|
|
{
|
|
MapNames.Mira => !(previous is SystemTypes.Laboratory or SystemTypes.Reactor && RoomGoal is SystemTypes.Laboratory or SystemTypes.Reactor) && (previous is SystemTypes.Laboratory or SystemTypes.Reactor || RoomGoal is SystemTypes.Laboratory or SystemTypes.Reactor),
|
|
MapNames.Polus => previous == SystemTypes.Specimens || RoomGoal == SystemTypes.Specimens,
|
|
_ => false
|
|
};
|
|
|
|
if (involvesDecontamination) time += 15;
|
|
|
|
switch (Main.CurrentMap)
|
|
{
|
|
case MapNames.Airship when RoomGoal == SystemTypes.Ventilation:
|
|
time = (int)(time * 0.4f);
|
|
break;
|
|
case MapNames.Fungle when RoomGoal == SystemTypes.Laboratory || previous == SystemTypes.Laboratory:
|
|
time += (int)(8 / speed);
|
|
break;
|
|
case MapNames.Polus when (RoomGoal == SystemTypes.Laboratory && previous is not SystemTypes.Storage and not SystemTypes.Specimens) || (previous == SystemTypes.Laboratory && RoomGoal is not SystemTypes.Office and not SystemTypes.Storage and not SystemTypes.Electrical):
|
|
time -= (int)(5 * speed);
|
|
break;
|
|
}
|
|
|
|
TimeLeft = Math.Max((int)Math.Round(time * GlobalTimeMultiplier.GetFloat()), 4);
|
|
if (Options.CurrentGameMode == CustomGameMode.AllInOne) TimeLeft *= AllInOneGameMode.RoomRushTimeLimitMultiplier.GetInt();
|
|
Logger.Info($"Starting a new round - Goal = from: {Translator.GetString(previous.ToString())}, to: {Translator.GetString(RoomGoal.ToString())} - Time: {TimeLeft} ({Main.CurrentMap})", "RoomRush");
|
|
Main.AllPlayerControls.Do(x => LocateArrow.RemoveAllTarget(x.PlayerId));
|
|
if (DisplayArrowToRoom.GetBool()) Main.AllPlayerControls.Do(x => LocateArrow.Add(x.PlayerId, goalPos));
|
|
|
|
Utils.NotifyRoles();
|
|
|
|
Main.AllPlayerSpeed[PlayerControl.LocalPlayer.PlayerId] = Main.MinSpeed;
|
|
PlayerControl.LocalPlayer.SyncSettings();
|
|
|
|
LateTask.New(() =>
|
|
{
|
|
Main.AllPlayerSpeed[PlayerControl.LocalPlayer.PlayerId] = speed;
|
|
PlayerControl.LocalPlayer.SyncSettings();
|
|
}, Utils.CalculatePingDelay() * 2f);
|
|
}
|
|
|
|
private static PlainShipRoom GetRoomClass(this SystemTypes systemTypes)
|
|
{
|
|
return ShipStatus.Instance.AllRooms.First(x => x.RoomId == systemTypes);
|
|
}
|
|
|
|
public static string GetSuffix(PlayerControl seer)
|
|
{
|
|
if (!GameGoing || Main.HasJustStarted || seer == null) return string.Empty;
|
|
|
|
StringBuilder sb = new();
|
|
bool dead = !seer.IsAlive();
|
|
bool done = dead || DonePlayers.Contains(seer.PlayerId);
|
|
Color color = done ? Color.green : Color.yellow;
|
|
|
|
if (DisplayRoomName.GetBool()) sb.Append(Utils.ColorString(color, Translator.GetString(RoomGoal.ToString())) + "\n");
|
|
if (DisplayArrowToRoom.GetBool()) sb.Append(Utils.ColorString(color, LocateArrow.GetArrows(seer)) + "\n");
|
|
|
|
color = done ? Color.white : Color.yellow;
|
|
sb.Append(Utils.ColorString(color, TimeLeft.ToString()) + "\n");
|
|
|
|
if (VentTimes.GetInt() == 0 || dead || seer.IsModClient()) return sb.ToString().Trim();
|
|
|
|
sb.Append('\n');
|
|
|
|
int vents = VentLimit.GetValueOrDefault(seer.PlayerId);
|
|
sb.Append(string.Format(Translator.GetString("RR_VentsRemaining"), vents));
|
|
|
|
return sb.ToString().Trim();
|
|
}
|
|
|
|
public static void ReceiveRPC(MessageReader reader)
|
|
{
|
|
switch (reader.ReadPackedInt32())
|
|
{
|
|
case 1:
|
|
int ventLimit = VentTimes.GetInt();
|
|
VentLimit = Main.AllPlayerControls.ToDictionary(x => x.PlayerId, _ => ventLimit);
|
|
break;
|
|
case 2:
|
|
int limit = reader.ReadPackedInt32();
|
|
byte id = reader.ReadByte();
|
|
VentLimit[id] = limit;
|
|
break;
|
|
}
|
|
}
|
|
|
|
[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.FixedUpdate))]
|
|
private static class FixedUpdatePatch
|
|
{
|
|
private static long LastUpdate = Utils.TimeStamp;
|
|
|
|
[SuppressMessage("ReSharper", "UnusedMember.Local")]
|
|
public static void Postfix(PlayerControl __instance)
|
|
{
|
|
if (!GameGoing || Main.HasJustStarted || !CustomGameMode.RoomRush.IsActiveOrIntegrated() || !AmongUsClient.Instance.AmHost || !GameStates.IsInTask || !__instance.IsHost()) return;
|
|
|
|
long now = Utils.TimeStamp;
|
|
PlayerControl[] aapc = Main.AllAlivePlayerControls;
|
|
|
|
foreach (PlayerControl pc in aapc)
|
|
{
|
|
PlainShipRoom room = pc.GetPlainShipRoom();
|
|
|
|
bool notAllInOne = Options.CurrentGameMode != CustomGameMode.AllInOne;
|
|
|
|
if (pc.IsAlive() && !pc.inMovingPlat && room != null && room.RoomId == RoomGoal && DonePlayers.Add(pc.PlayerId))
|
|
{
|
|
Logger.Info($"{pc.GetRealName()} entered the correct room", "RoomRush");
|
|
pc.Notify($"{DonePlayers.Count}.", 2f);
|
|
|
|
int timeLeft = TimeWhenFirstPlayerEntersRoom.GetInt();
|
|
|
|
if (DonePlayers.Count == 2 && timeLeft < TimeLeft && (notAllInOne || !AllInOneGameMode.RoomRushDontLowerTimeLimitWhenTwoPlayersEnterCorrectRoom.GetBool()))
|
|
{
|
|
Logger.Info($"Two players entered the correct room, setting the timer to {timeLeft}", "RoomRush");
|
|
TimeLeft = timeLeft;
|
|
LastUpdate = now;
|
|
|
|
if (aapc.Length == 2 && pc.IsLocalPlayer())
|
|
Achievements.Type.WheresTheBlueShell.CompleteAfterGameEnd();
|
|
}
|
|
|
|
if (DonePlayers.Count == aapc.Length - 1 && (notAllInOne || !AllInOneGameMode.RoomRushDontKillLastPlayer.GetBool()))
|
|
{
|
|
PlayerControl last = aapc.First(x => !DonePlayers.Contains(x.PlayerId));
|
|
Logger.Info($"All players entered the correct room except one, killing the last player ({last.GetRealName()})", "RoomRush");
|
|
last.Suicide();
|
|
last.Notify(Translator.GetString("RR_YouWereLast"));
|
|
StartNewRound();
|
|
return;
|
|
}
|
|
}
|
|
else if ((room == null || room.RoomId != RoomGoal) && (notAllInOne || !AllInOneGameMode.RoomRushDontKillPlayersOutsideRoomWhenTimeRunsOut.GetBool()))
|
|
DonePlayers.Remove(pc.PlayerId);
|
|
}
|
|
|
|
if (LastUpdate == now) return;
|
|
|
|
LastUpdate = now;
|
|
|
|
TimeLeft--;
|
|
Utils.NotifyRoles();
|
|
|
|
if (TimeLeft <= 0)
|
|
{
|
|
Logger.Info("Time is up, killing everyone who didn't enter the correct room", "RoomRush");
|
|
PlayerControl[] lateAapc = Main.AllAlivePlayerControls;
|
|
PlayerControl[] playersOutsideRoom = lateAapc.ExceptBy(DonePlayers, x => x.PlayerId).ToArray();
|
|
if (playersOutsideRoom.Length == lateAapc.Length) CustomWinnerHolder.ResetAndSetWinner(CustomWinner.None);
|
|
|
|
playersOutsideRoom.Do(x => x.Suicide());
|
|
StartNewRound();
|
|
|
|
if (playersOutsideRoom.Any(x => x.IsLocalPlayer()))
|
|
Achievements.Type.OutOfTime.Complete();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public class RRPlayer : RoleBase
|
|
{
|
|
public override bool IsEnable => CustomGameMode.RoomRush.IsActiveOrIntegrated();
|
|
|
|
public override void Init() { }
|
|
|
|
public override void Add(byte playerId) { }
|
|
|
|
public override void SetupCustomOption() { }
|
|
|
|
public override void OnExitVent(PlayerControl pc, Vent vent)
|
|
{
|
|
RoomRush.VentLimit[pc.PlayerId]--;
|
|
Utils.SendRPC(CustomRPC.RoomRushDataSync, 2, RoomRush.VentLimit[pc.PlayerId], pc.PlayerId);
|
|
if (RoomRush.VentLimit[pc.PlayerId] <= 0) pc.RpcChangeRoleBasis(CustomRoles.RRPlayer);
|
|
}
|
|
}
|
|
} |