public static void CallQueuedCommand(string user, [Group(1)] bool now, [Group(2)] string name) { name = (name?.Trim()) ?? ""; var response = TwitchGame.Instance.CheckIfCall(false, now, user, name, out bool callChanged); if (response != TwitchGame.CallResponse.Success) { TwitchGame.Instance.SendCallResponse(user, name, response, callChanged); return; } if (callChanged) { IRCConnection.SendMessageFormat("@{0}, your call has been changed to {1}.", user, string.IsNullOrEmpty(name) ? "the next queued command" : name); } TwitchGame.Instance.CommandQueue.Remove(TwitchGame.Instance.callSend); TwitchGame.ModuleCameras?.SetNotes(); IRCConnection.SendMessageFormat("{0} {1}: {2}", TwitchGame.Instance.callWaiting && string.IsNullOrEmpty(user) ? "Call waiting, calling" : now ? "Bypassing the required number of calls, calling" : TwitchGame.Instance.callsNeeded > 1 ? "Required calls reached, calling" : "Calling", TwitchGame.Instance.callSend.Message.UserNickName, TwitchGame.Instance.callSend.Message.Text); DeleteCallInformation(true); IRCConnection.ReceiveMessage(TwitchGame.Instance.callSend.Message); }
public static void Unclaim(TwitchModule module, string user, [Group(1)] string cmd) { if (module.Solved) { IRCConnection.SendMessageFormat(TwitchPlaySettings.data.AlreadySolved, module.Code, module.PlayerName, user, module.HeaderText); return; } // If module is already unclaimed, just remove from claim queue if (module.PlayerName == null) { module.RemoveFromClaimQueue(user); return; } // Error if a non-mod tries to unclaim someone else’s module if (!UserAccess.HasAccess(user, AccessLevel.Mod, true) && module.PlayerName != user) { IRCConnection.SendMessage($"{user}, module {module.Code} ({module.HeaderText}) is not claimed by you."); return; } module.SetUnclaimed(); if (cmd.Contains("v")) { TwitchGame.ModuleCameras?.UnviewModule(module); } }
public static void Mine(TwitchModule module, string user, bool isWhisper) { if (isWhisper) { IRCConnection.SendMessage($"@{user}, using mine on modules is not allowed in whispers.", user, false); return; } // The module belongs to this user and there’s a takeover attempt in progress: cancel the takeover attempt if (module.PlayerName == user && module.TakeInProgress != null) { IRCConnection.SendMessageFormat(TwitchPlaySettings.data.ModuleIsMine, module.PlayerName, module.Code, module.HeaderText); module.StopCoroutine(module.TakeInProgress); module.TakeInProgress = null; module.TakeUser = null; } // The module isn’t claimed: just claim it else if (module.PlayerName == null) { IRCConnection.SendMessage(module.TryClaim(user).Message); } // Someone else has a claim on the module else if (module.PlayerName != user) { IRCConnection.SendMessageFormat(TwitchPlaySettings.data.AlreadyClaimed, module.Code, module.PlayerName, user, module.HeaderText); } // If the user has a claim on the module but there’s no takeover attempt, just ignore this command }
private IEnumerator EndTrainingModeBomb() { TrainingModeRemainingTime = TwitchPlaySettings.data.TrainingModeDetonationTime; if (TrainingModeRemainingTime < 1) { yield break; } while (true) { if (TrainingModeAlertTimes.Contains(TrainingModeRemainingTime)) { if (alertSound != null) { alertSound.Play(); } IRCConnection.SendMessageFormat("Warning: This bomb will be automatically detonated in {0} minute{1}.", TrainingModeRemainingTime.ToString(), TrainingModeRemainingTime == 1 ? "" : "s"); } yield return(new WaitForSecondsRealtime(60.0f)); TrainingModeRemainingTime--; if (BombActive) { ModuleCameras.SetNotes(); } if (TrainingModeRemainingTime < 1) { Bombs[0].CauseExplosionByTrainingModeTimeout(); } } }
public static void BombTurnAround(TwitchModule module) { if (!module.Solver.TurnQueued) { module.Solver.TurnQueued = true; module.StartCoroutine(module.Solver.TurnBombOnSolve()); } IRCConnection.SendMessageFormat(TwitchPlaySettings.data.TurnBombOnSolve, module.Code, module.HeaderText); }
public static void DeleteCallInformation(bool silent) { TwitchGame.Instance.CallingPlayers.Clear(); TwitchGame.Instance.callWaiting = false; if (!silent) { IRCConnection.SendMessageFormat("All call information cleared."); } }
public static void RemoveQueuedPlayer(string user) { if (!TwitchGame.Instance.CallingPlayers.Contains(user)) { IRCConnection.SendMessageFormat("@{0}, you haven't called yet!", user); return; } TwitchGame.Instance.CallingPlayers.Remove(user); IRCConnection.SendMessageFormat("@{0}, your call has been removed.", user); CallCountCommand(); }
private static IEnumerator RunModuleCommand(TwitchModule module, string user, string cmd) { if (module.Solver == null) { yield break; } if (module.Solved && !TwitchPlaySettings.data.AnarchyMode) { IRCConnection.SendMessageFormat(TwitchPlaySettings.data.AlreadySolved, module.Code, module.PlayerName, user, module.HeaderText); yield break; } if (module.Bomb.BackdoorComponent != null && module.Bomb.BackdoorComponent.GetValue <bool>("BeingHacked") && module.BombComponent.GetModuleDisplayName() != "Backdoor Hacking") { IRCConnection.SendMessageFormat(TwitchPlaySettings.data.BackdoorHackingBlock, module.Code, user, module.HeaderText); yield break; } Transform tsLight = module.BombComponent.StatusLightParent?.transform.Find("statusLight(Clone)").Find("Component_LED_ERROR(Clone)"); if (tsLight != null && tsLight.gameObject.activeSelf) { IRCConnection.SendMessageFormat(TwitchPlaySettings.data.TechSupportBlock, module.Code, user, module.HeaderText); yield break; } // We’re allowed to interact with this module if either: if ( // the module is unclaimed; module.PlayerName == null || // the module is claimed by the player; module.PlayerName == user || // anarchy mode is on; TwitchPlaySettings.data.AnarchyMode || // there is less than X time left on the clock; module.Bomb.CurrentTimer <= TwitchPlaySettings.data.MinTimeLeftForClaims || // there are only X unsolved modules left. TwitchGame.Instance.Modules.Count(x => !x.Solved && GameRoom.Instance.IsCurrentBomb(x.BombID)) < TwitchPlaySettings.data.MinUnsolvedModulesLeftForClaims ) { var response = module.Solver.RespondToCommand(user, cmd); while (response.MoveNext()) { yield return(response.Current); } module.Solver.EnableAnarchyStrike(); } else { IRCConnection.SendMessageFormat(TwitchPlaySettings.data.AlreadyClaimed, module.Code, module.PlayerName, user, module.HeaderText); } }
public static void CallSetCommand(string user, [Group(1)] int minimum) { if (minimum <= 0 || minimum >= 25) { IRCConnection.SendMessageFormat("@{0}, {1} is in invalid number of calls!", user, minimum); return; } TwitchGame.Instance.callsNeeded = minimum; TwitchGame.Instance.CallingPlayers.Clear(); IRCConnection.SendMessageFormat("Set minimum calls to {0}.", minimum); }
public static void ListCalledPlayers(string user) { int totalCalls = TwitchGame.Instance.CallingPlayers.Count; if (totalCalls == 0) { IRCConnection.SendMessageFormat("@{0}, no calls have been made.", user); return; } string CallPlayers = string.Join(", @", TwitchGame.Instance.CallingPlayers.ToArray()); IRCConnection.SendMessageFormat("These players have already called: @{0}", CallPlayers); }
public void SendCallResponse(string user, string name, CallResponse response, bool callChanged) { bool unnamed = string.IsNullOrEmpty(name); if (response == CallResponse.AlreadyCalled) { IRCConnection.SendMessageFormat("@{0}, you already called!", user); return; } else if (response == CallResponse.NotEnoughCalls) { if (callChanged) { IRCConnection.SendMessageFormat("@{0}, your call has been updated to {1}.", user, unnamed ? "the next queued command" : name); } GameCommands.CallCountCommand(); return; } else if (response == CallResponse.UncommonCalls) { if (callChanged) { IRCConnection.SendMessageFormat("@{0}, your call has been updated to {1}. Uncommon calls still present.", user, unnamed ? "the next queued command" : name); } else { IRCConnection.SendMessageFormat("Sorry, uncommon calls were made. Please either correct your call(s) or use “!callnow” followed by the correct command to call."); GameCommands.ListCalledPlayers(); } return; } else if (response == CallResponse.DifferentName) { CommandQueueItem call = CommandQueue.Find(item => item.Message.Text.StartsWith(name)); IRCConnection.SendMessageFormat("@{0}, module {1} is queued with the name “{2}”, please use “!call {2}” to call it.", user, name, call.Name); return; } else { unnamed = string.IsNullOrEmpty(commandToCall); if (callWaiting) { IRCConnection.SendMessageFormat("Waiting for {0} to be queued.", unnamed ? "the next unnamed queued command" : commandToCall.StartsWith("!") ? "module " + commandToCall : "the command named “" + commandToCall + "”"); } else { IRCConnection.SendMessageFormat("No {0} in the queue. Calling {1} when it is queued.", unnamed ? "unnamed commands" : commandToCall.StartsWith("!") ? "command for module " + commandToCall : "command named “" + commandToCall + "”", unnamed ? "the next unnamed queued command" : commandToCall.StartsWith("!") ? "module " + commandToCall : "the command named “" + commandToCall + "”"); callWaiting = true; } } }
public static void DeleteQueuedPlayer([Group(1)] string callUser, string user) { if (string.IsNullOrEmpty(callUser)) { IRCConnection.SendMessageFormat("@{0}, please specify a call to remove!", user); } else if (!TwitchGame.Instance.CallingPlayers.Keys.Contains(user)) { IRCConnection.SendMessageFormat("@{0}, @{1} has not called!", user, callUser); } else { TwitchGame.Instance.CallingPlayers.Remove(callUser); IRCConnection.SendMessageFormat("@{0}, removed @{1}'s call.", user, callUser); TwitchGame.Instance.CallUpdate(true); } }
public static void CallAllQueuedCommands(string user, bool isWhisper) { if (TwitchGame.Instance.CommandQueue.Count == 0) { IRCConnection.SendMessage($"{user}, the queue is empty.", user, !isWhisper); return; } // Take a copy of the list in case executing one of the commands modifies the command queue var allCommands = TwitchGame.Instance.CommandQueue.ToList(); TwitchGame.Instance.CommandQueue.Clear(); TwitchGame.ModuleCameras?.SetNotes(); foreach (var call in allCommands) { IRCConnection.SendMessageFormat("Calling {0}: {1}", call.Message.UserNickName, call.Message.Text); IRCConnection.ReceiveMessage(call.Message); } }
public static void ListCalledPlayers() { int totalCalls = TwitchGame.Instance.CallingPlayers.Count; if (totalCalls == 0) { IRCConnection.SendMessageFormat("No calls have been made."); return; } string[] __calls = TwitchGame.Instance.CallingPlayers.Values.ToArray(); string[] __callPlayers = TwitchGame.Instance.CallingPlayers.Keys.ToArray(); string builder = ""; for (int j = 0; j < __calls.Length; j++) { builder = builder + ((j == 0) ? "@" : ", @") + __callPlayers[j] + ": " + (string.IsNullOrEmpty(__calls[j]) ? "Next queued command" : __calls[j]); } IRCConnection.SendMessageFormat("These players have already called: {0}", builder); }
public static void Take(TwitchModule module, string user, bool isWhisper) { if (isWhisper) { IRCConnection.SendMessageFormat("Sorry {0}, taking modules is not allowed in whispers.", user); } else if (TwitchPlaySettings.data.AnarchyMode) { IRCConnection.SendMessageFormat("Sorry {0}, taking modules is not allowed in anarchy mode.", user); } // Attempt to take over from another user else if (module.PlayerName != null && user != module.PlayerName) { module.AddToClaimQueue(user); if (module.TakeInProgress == null) { IRCConnection.SendMessageFormat(TwitchPlaySettings.data.TakeModule, module.PlayerName, user, module.Code, module.HeaderText); module.TakeInProgress = module.TakeModule(); module.StartCoroutine(module.TakeInProgress); } else { IRCConnection.SendMessageFormat(TwitchPlaySettings.data.TakeInProgress, user, module.Code, module.HeaderText); } } // Module is already claimed by the same user else if (module.PlayerName != null) { if (!module.PlayerName.Equals(user)) { module.AddToClaimQueue(user); } IRCConnection.SendMessageFormat(TwitchPlaySettings.data.ModuleAlreadyOwned, user, module.Code, module.HeaderText); } // Module is not claimed at all: just claim it else { IRCConnection.SendMessage(module.ClaimModule(user).Second); } }
public static void Assign(TwitchModule module, string user, [Group(1)] string targetUser) { if (TwitchPlaySettings.data.AnarchyMode) { IRCConnection.SendMessageFormat("Sorry {0}, assigning modules is not allowed in anarchy mode.", user); return; } if (module.TakeInProgress != null) { module.StopCoroutine(module.TakeInProgress); module.TakeInProgress = null; } module.PlayerName = targetUser; module.RemoveFromClaimQueue(user); module.CanClaimNow(user, true, true); module.SetBannerColor(module.ClaimedBackgroundColour); IRCConnection.SendMessageFormat(TwitchPlaySettings.data.AssignModule, module.Code, module.PlayerName, user, module.HeaderText); }
private static IEnumerator RunModuleCommand(TwitchModule module, string user, string cmd, bool zoom) { if (module.Solver == null) { yield break; } if (module.Solved && !TwitchPlaySettings.data.AnarchyMode) { IRCConnection.SendMessageFormat(TwitchPlaySettings.data.AlreadySolved, module.Code, module.PlayerName, user, module.HeaderText); yield break; } // We’re allowed to interact with this module if either: if ( // the module is unclaimed; module.PlayerName == null || // the module is claimed by the player; module.PlayerName == user || // anarchy mode is on; TwitchPlaySettings.data.AnarchyMode || // there is less than X time left on the clock; module.Bomb.CurrentTimer <= TwitchPlaySettings.data.MinTimeLeftForClaims || // there are only X unsolved modules left. TwitchGame.Instance.Modules.Count(x => !x.Solved && GameRoom.Instance.IsCurrentBomb(x.BombID)) < TwitchPlaySettings.data.MinUnsolvedModulesLeftForClaims ) { yield return(new WaitForSeconds(0.1f)); var response = module.Solver.RespondToCommand(user, cmd, zoom); while (response.MoveNext()) { yield return(response.Current); } yield return(new WaitForSeconds(0.1f)); } else { IRCConnection.SendMessageFormat(TwitchPlaySettings.data.AlreadyClaimed, module.Code, module.PlayerName, user, module.HeaderText); } }
public void CallUpdate(bool response) { var callResponse = CheckIfCall(true, false, "", commandToCall, out _); if (callResponse == CallResponse.Success) { GameCommands.CallQueuedCommand("", false, true, commandToCall); } else if (callResponse == CallResponse.NotPresent) { IRCConnection.SendMessageFormat("Waiting for {0} to be queued.", string.IsNullOrEmpty(commandToCall) ? "the next unnamed queued command" : commandToCall.StartsWith("!") ? "module " + commandToCall : "the command named “" + commandToCall + "”"); } else { callWaiting = false; } if (response) { GameCommands.CallCountCommand(); } }
public static void Take(TwitchModule module, string user, bool isWhisper) { if (isWhisper) { IRCConnection.SendMessage($"@{user}, taking modules is not allowed in whispers."); } else if (TwitchPlaySettings.data.AnarchyMode) { IRCConnection.SendMessage($"@{user}, taking modules is not allowed in anarchy mode."); } // Module is already claimed by the same user else if (module.PlayerName == user) { IRCConnection.SendMessageFormat(TwitchPlaySettings.data.ModuleAlreadyOwned, user, module.Code, module.HeaderText); } // Module is not claimed at all: just claim it else if (module.PlayerName == null) { IRCConnection.SendMessage(module.TryClaim(user).Message); } // Attempt to take over from another user else { module.AddToClaimQueue(user); if (module.TakeInProgress != null) { IRCConnection.SendMessageFormat(TwitchPlaySettings.data.TakeInProgress, user, module.Code, module.HeaderText); } else { IRCConnection.SendMessageFormat(TwitchPlaySettings.data.TakeModule, module.PlayerName, user, module.Code, module.HeaderText); module.TakeUser = user; module.TakeInProgress = module.StartCoroutine(module.ProcessTakeover()); } } }
public static void Assign(TwitchModule module, string user, [Group(1)] string targetUser) { targetUser = targetUser.FormatUsername(); if (module.PlayerName == targetUser) { IRCConnection.SendMessage($"{user}, the module is already assigned to {targetUser}."); return; } if (TwitchPlaySettings.data.AnarchyMode) { IRCConnection.SendMessage($"{user}, assigning modules is not allowed in anarchy mode."); return; } if (!UserAccess.HasAccess(user, AccessLevel.Mod, true)) { if (module.PlayerName != user || !module.ClaimQueue.Any(q => q.UserNickname == targetUser)) { IRCConnection.SendMessage($"{user}, {module.Code} can only be reassigned if you have it claimed and the other user is in its claim queue."); return; } if (TwitchGame.Instance.Modules.Count(md => !md.Solved && targetUser.EqualsIgnoreCase(md.PlayerName)) >= TwitchPlaySettings.data.ModuleClaimLimit) { IRCConnection.SendMessage($"{user}, {module.Code} cannot be reassigned because it would take the other user above their claim limit."); return; } } if (module.TakeInProgress != null) { module.StopCoroutine(module.TakeInProgress); module.TakeInProgress = null; module.TakeUser = null; } module.SetClaimedBy(targetUser); IRCConnection.SendMessageFormat(TwitchPlaySettings.data.AssignModule, module.Code, module.PlayerName, user, module.HeaderText); }
public static void Solved(TwitchModule module, string user) { module.SetBannerColor(module.SolvedBackgroundColor); module.PlayerName = null; IRCConnection.SendMessageFormat(TwitchPlaySettings.data.ModuleReady, module.Code, user, module.HeaderText); }
public void ReportState() => IRCConnection.SendMessageFormat("Elevator is {0}", GameplayState.GameplayRoomPrefabOverride == null ? (ElevatorRoomGameObject == null ? "not loaded" : "off") : "on");
private IEnumerator SetupRoomElevatorSwitch() { SetupRoom setupRoom = SceneManager.Instance.CurrentRoom as SetupRoom; if (setupRoom == null) { yield break; } try { ElevatorRoomGameObject = Resources.Load <GameObject>("PC/Prefabs/ElevatorRoom/ElevatorBombRoom"); } catch (Exception ex) { DebugHelper.LogException(ex, "Can't load the Elevator room prefab."); gameObject.SetActive(false); yield break; } if (setupRoom.ElevatorSwitch == null) { ElevatorSwitch.OnInteract += OnInteract; ElevatorLEDOn.SetActive(IsON); ElevatorLEDOff.SetActive(!IsON); ElevatorSwitch.transform.localEulerAngles = new Vector3(IsON ? 55 : -55, 0, 0); yield break; } ElevatorSwitch elevatorSwitch = setupRoom.ElevatorSwitch; DebugHelper.Log("Found an Elevator switch, Activating it now"); try { elevatorSwitch.GetComponentInChildren <Selectable>(true).SelectableArea.ActivateSelectableArea(); elevatorSwitch.Switch.SetInitialState(GameplayState.GameplayRoomPrefabOverride != null); elevatorSwitch.LEDOn.SetActive(GameplayState.GameplayRoomPrefabOverride != null); elevatorSwitch.LEDOff.SetActive(GameplayState.GameplayRoomPrefabOverride == null); elevatorSwitch.Switch.OnToggle += toggleState => { DebugHelper.Log($"Toggle State = {toggleState}"); if (elevatorSwitch.On() && IRCConnection.Instance.State != IRCConnectionState.Connected) { elevatorSwitch.Switch.Toggle(); Audio.PlaySound(KMSoundOverride.SoundEffect.Strike, elevatorSwitch.Switch.transform); return; } GameplayState.GameplayRoomPrefabOverride = toggleState ? ElevatorRoomGameObject : null; IRCConnection.SendMessageFormat("Elevator is {0}", GameplayState.GameplayRoomPrefabOverride == null ? (ElevatorRoomGameObject == null ? "not loaded" : "off") : "on"); elevatorSwitch.LEDOn.SetActive(GameplayState.GameplayRoomPrefabOverride != null); elevatorSwitch.LEDOff.SetActive(GameplayState.GameplayRoomPrefabOverride == null); }; } catch (Exception ex) { DebugHelper.LogException(ex, "Could not activate elevator switch due to an exception:"); yield break; } elevatorSwitch.gameObject.SetActive(true); yield return(null); yield return(null); elevatorSwitch.gameObject.SetActive(true); gameObject.SetActive(false); }
public void PostToChat(string analysisUrl, string format = "Analysis for this bomb: {0}", string emote = "copyThis") => IRCConnection.SendMessageFormat($"{emote} {format}", analysisUrl);
private bool AttemptInvokeCommand <TObj>(StaticCommand command, IRCMessage msg, string cmdStr, Match m, TObj extraObject) { if (command.HasAttribute <DebuggingOnlyAttribute>() && !TwitchPlaySettings.data.EnableDebuggingCommands) { return(false); } if (command.HasAttribute <ElevatorOnlyAttribute>() && !(GameRoom.Instance is ElevatorGameRoom)) { return(false); } if (command.HasAttribute <ElevatorDisallowedAttribute>() && GameRoom.Instance is ElevatorGameRoom) { return(false); } if (!UserAccess.HasAccess(msg.UserNickName, TwitchPlaySettings.data.AnarchyMode ? command.Attr.AccessLevelAnarchy : command.Attr.AccessLevel, orHigher: true)) { IRCConnection.SendMessageFormat("@{0}, you need {1} access to use that command{2}.", msg.UserNickName, UserAccess.LevelToString(TwitchPlaySettings.data.AnarchyMode ? command.Attr.AccessLevelAnarchy : command.Attr.AccessLevel), TwitchPlaySettings.data.AnarchyMode ? " in anarchy mode" : ""); // Return true so that the command counts as processed return(true); } if (extraObject is TwitchModule mdl && mdl.Solved && !command.HasAttribute <SolvedAllowedAttribute>() && !TwitchPlaySettings.data.AnarchyMode) { IRCConnection.SendMessageFormat(TwitchPlaySettings.data.AlreadySolved, mdl.Code, mdl.PlayerName, msg.UserNickName, mdl.BombComponent.GetModuleDisplayName()); // Return true so that the command counts as processed (otherwise you get the above message multiple times) return(true); } Leaderboard.Instance.GetRank(msg.UserNickName, out Leaderboard.LeaderboardEntry entry); if (entry?.Team == null && extraObject is TwitchModule && OtherModes.VSModeOn) { IRCConnection.SendMessage($@"{msg.UserNickName}, you have not joined a team, and cannot solve modules in this mode until you do, please use !join evil or !join good."); // Return true so that the command counts as processed (otherwise you get the above message multiple times) return(true); } if (!TwitchGame.IsAuthorizedDefuser(msg.UserNickName, msg.IsWhisper)) { return(true); } BanData ban = UserAccess.IsBanned(msg.UserNickName); if (ban != null) { if (double.IsPositiveInfinity(ban.BanExpiry)) { IRCConnection.SendMessage($"Sorry @{msg.UserNickName}, You were banned permanently from Twitch Plays by {ban.BannedBy}{(string.IsNullOrEmpty(ban.BannedReason) ? "." : $", for the following reason: {ban.BannedReason}")}", msg.UserNickName, !msg.IsWhisper); } else { int secondsRemaining = (int)(ban.BanExpiry - DateTime.Now.TotalSeconds()); int daysRemaining = secondsRemaining / 86400; secondsRemaining %= 86400; int hoursRemaining = secondsRemaining / 3600; secondsRemaining %= 3600; int minutesRemaining = secondsRemaining / 60; secondsRemaining %= 60; string timeRemaining = $"{secondsRemaining} seconds."; if (daysRemaining > 0) { timeRemaining = $"{daysRemaining} days, {hoursRemaining} hours, {minutesRemaining} minutes, {secondsRemaining} seconds."; } else if (hoursRemaining > 0) { timeRemaining = $"{hoursRemaining} hours, {minutesRemaining} minutes, {secondsRemaining} seconds."; } else if (minutesRemaining > 0) { timeRemaining = $"{minutesRemaining} minutes, {secondsRemaining} seconds."; } IRCConnection.SendMessage($"Sorry @{msg.UserNickName}, You were timed out from Twitch Plays by {ban.BannedBy}{(string.IsNullOrEmpty(ban.BannedReason) ? "." : $", For the following reason: {ban.BannedReason}")} You can participate again in {timeRemaining}", msg.UserNickName, !msg.IsWhisper); } return(true); } var parameters = command.Method.GetParameters(); var groupAttrs = parameters.Select(p => (GroupAttribute)p.GetCustomAttributes(typeof(GroupAttribute), false).FirstOrDefault()).ToArray(); var arguments = new object[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { // Capturing groups from the regular expression if (groupAttrs[i] != null && m != null) { var group = m.Groups[groupAttrs[i].GroupIndex]; NumberParseResult result; // Helper function to parse numbers (ints, floats, doubles) NumberParseResult IsNumber <TNum>(TryParse <TNum> tryParse) { var isNullable = parameters[i].ParameterType == typeof(Nullable <>).MakeGenericType(typeof(TNum)); if (parameters[i].ParameterType != typeof(TNum) && !isNullable) { return(NumberParseResult.NotOfDesiredType); } if (group.Success && tryParse(group.Value, out TNum rslt)) { arguments[i] = rslt; return(NumberParseResult.Success); } if (isNullable) { return(NumberParseResult.Success); } IRCConnection.SendMessage(group.Success ? "@{0}, “{1}” is not a valid number." : "@{0}, the command could not be parsed.", msg.UserNickName, !msg.IsWhisper, msg.UserNickName, group.Success ? group.Value : null); return(NumberParseResult.Error); } // Strings if (parameters[i].ParameterType == typeof(string)) { arguments[i] = m.Success ? group.Value : null; } // Booleans — only specifies whether the group matched or not else if (parameters[i].ParameterType == typeof(bool)) { arguments[i] = group.Success; } // Numbers (int, float, double); includes nullables else if ( (result = IsNumber <int>(int.TryParse)) != NumberParseResult.NotOfDesiredType || (result = IsNumber <float>(float.TryParse)) != NumberParseResult.NotOfDesiredType || (result = IsNumber <double>(double.TryParse)) != NumberParseResult.NotOfDesiredType) { if (result == NumberParseResult.Error) { return(true); } } } // Built-in parameter names else if (parameters[i].ParameterType == typeof(string) && parameters[i].Name == "user") { arguments[i] = msg.UserNickName; } else if (parameters[i].ParameterType == typeof(string) && parameters[i].Name == "cmd") { arguments[i] = cmdStr; } else if (parameters[i].ParameterType == typeof(bool) && parameters[i].Name == "isWhisper") { arguments[i] = msg.IsWhisper; } else if (parameters[i].ParameterType == typeof(IRCMessage)) { arguments[i] = msg; } else if (parameters[i].ParameterType == typeof(KMGameInfo)) { arguments[i] = GetComponent <KMGameInfo>(); } else if (parameters[i].ParameterType == typeof(KMGameInfo.State)) { arguments[i] = CurrentState; } else if (parameters[i].ParameterType == typeof(FloatingHoldable) && extraObject is TwitchHoldable twitchHoldable) { arguments[i] = twitchHoldable.Holdable; } // Object we passed in (module, bomb, holdable) else if (parameters[i].ParameterType.IsAssignableFrom(typeof(TObj))) { arguments[i] = extraObject; } else if (parameters[i].IsOptional) { arguments[i] = parameters[i].DefaultValue; } else { IRCConnection.SendMessage("@{0}, this is a bug; please notify the devs. Error: the “{1}” command has an unrecognized parameter “{2}”. It expects a type of “{3}”, and the extraObject is of type “{4}”.", msg.UserNickName, !msg.IsWhisper, msg.UserNickName, command.Method.Name, parameters[i].Name, parameters[i].ParameterType.Name, extraObject?.GetType().Name); return(true); } } var invokeResult = command.Method.Invoke(null, arguments); if (invokeResult is bool invRes) { return(invRes); } else if (invokeResult is IEnumerator coroutine) { ProcessCommandCoroutine(coroutine, extraObject); } else if (invokeResult != null) { IRCConnection.SendMessage("@{0}, this is a bug; please notify the devs. Error: the “{1}” command returned something unrecognized.", msg.UserNickName, !msg.IsWhisper, msg.UserNickName, command.Method.Name); } if ((TwitchPlaySettings.data.AnarchyMode ? command.Attr.AccessLevelAnarchy : command.Attr.AccessLevel) > AccessLevel.Defuser) { AuditLog.Log(msg.UserNickName, UserAccess.HighestAccessLevel(msg.UserNickName), msg.Text); } return(true); }
public static void BombTurnAroundCancel(TwitchModule module) { module.Solver.TurnQueued = false; IRCConnection.SendMessageFormat(TwitchPlaySettings.data.CancelBombTurn, module.Code, module.HeaderText); }
public static void FindClaimView([Group(1)] string commands, [Group(2)] string queries, string user, bool isWhisper) { var claim = commands.ContainsIgnoreCase("claim"); var view = commands.ContainsIgnoreCase("view"); var terms = queries.SplitFull(',', ';').Select(q => q.Trim()).Distinct().ToArray(); if (terms.Length > TwitchPlaySettings.data.FindClaimTerms && claim && TwitchPlaySettings.data.FindClaimTerms != -1) { IRCConnection.SendMessageFormat("@{0}, please reduce the size of your list to {1} or fewer terms.", user, TwitchPlaySettings.data.FindClaimTerms); // Prevents lists greater than length of 3 while using !claim return; } var modules = FindModules(terms).ToList(); if (!modules.Any()) { IRCConnection.SendMessage("No such modules.", user, !isWhisper); return; } if (claim) { if (!TwitchGame.Instance.FindClaimPlayers.ContainsKey(user)) { TwitchGame.Instance.FindClaimPlayers.Add(user, 0); } var _prevClaims = TwitchGame.Instance.FindClaimPlayers[user]; var _allowedClaims = TwitchGame.Instance.FindClaimUse; var _remainingClaims = _allowedClaims - _prevClaims; if (_remainingClaims < 1 && TwitchPlaySettings.data.FindClaimLimit != -1) { IRCConnection.SendMessageFormat("@{0}, you have no more findclaim uses.", user); return; } if (modules.Count > _remainingClaims && TwitchPlaySettings.data.FindClaimLimit != -1) { IRCConnection.SendMessageFormat("@{0}, that goes over your current findclaim limit of {1}. You will receive the first {2} claims.", user, _allowedClaims, _remainingClaims); ClaimViewPin(user, isWhisper, modules.Take(_remainingClaims), claim: claim, view: view); } else { ClaimViewPin(user, isWhisper, modules, claim: claim, view: view); } TwitchGame.Instance.FindClaimPlayers[user] = _prevClaims + modules.Count; } else if (view) { ClaimViewPin(user, isWhisper, modules, claim: claim, view: view); } else { // Neither claim nor view: just “find”, so output top 3 search results IRCConnection.SendMessage("{0}, modules ({2} total) are: {1}", user, !isWhisper, user, modules.Take(3).Select(handle => string.Format("{0} ({1}) - {2}", handle.HeaderText, handle.Code, handle.Solved ? "solved" : handle.PlayerName == null ? "unclaimed" : "claimed by " + handle.PlayerName)).Join(", "), modules.Count); } }
public static void CallQueuedCommand(string user, bool isWhisper, [Group(1)] bool now, [Group(2)] string name) { name = name?.Trim(); if (TwitchGame.Instance.CallingPlayers.Contains(user)) { IRCConnection.SendMessageFormat("@{0}, you already called!", user); return; } var _callsNeeded = TwitchGame.Instance.callsNeeded; var _callsTotal = TwitchGame.Instance.CallingPlayers.Count; // Only call if there are enough calls. if (!(_callsTotal + 1 >= _callsNeeded) && !now) { TwitchGame.Instance.CallingPlayers.Add(user); CallCountCommand(); return; } CommandQueueItem call = null; if (string.IsNullOrEmpty(name)) { // Call the first unnamed item in the queue. call = TwitchGame.Instance.CommandQueue.Find(item => item.Name == null); if (call == null) { IRCConnection.SendMessage($"@{user}, no unnamed commands in the queue.", user, !isWhisper); return; } } else if (name.StartsWith("!")) { name += ' '; // Call an unnamed item in the queue for a specific module. call = TwitchGame.Instance.CommandQueue.Find(item => item.Message.Text.StartsWith(name) && item.Name == null); if (call == null) { // If a named command exists, and no unnamed commands exist, then show the name of that command (but don't call it). call = TwitchGame.Instance.CommandQueue.Find(item => item.Message.Text.StartsWith(name)); if (call != null) { IRCConnection.SendMessage($"@{user}, module {name} is queued with the name “{call.Name}”, please use “!call {call.Name}” to call it.", user, !isWhisper); } else { IRCConnection.SendMessage($"@{user}, no commands for module {name} in the queue.", user, !isWhisper); } return; } } else { // Call a named item in the queue. call = TwitchGame.Instance.CommandQueue.FirstOrDefault(item => name.EqualsIgnoreCase(item.Name)); if (call == null) { IRCConnection.SendMessage($"@{user}, no commands named “{name}” in the queue.", user, !isWhisper); return; } } TwitchGame.Instance.CallingPlayers.Clear(); TwitchGame.Instance.CommandQueue.Remove(call); TwitchGame.ModuleCameras?.SetNotes(); IRCConnection.SendMessageFormat("{0} {1}: {2}", now ? "Bypassing the required number of calls, calling" : TwitchGame.Instance.callsNeeded > 1 ? "Required calls reached, calling" : "Calling", call.Message.UserNickName, call.Message.Text); IRCConnection.ReceiveMessage(call.Message); }
private void AwardStrikes(string userNickName, int strikeCount) { TwitchBomb bomb = TwitchGame.Instance.Bombs[0]; int strikePenalty = -5; strikePenalty = TwitchPlaySettings.data.EnableRewardMultipleStrikes ? (strikeCount * strikePenalty) : (Math.Min(strikePenalty, strikeCount * strikePenalty)); IRCConnection.SendMessageFormat(TwitchPlaySettings.data.AwardHoldableStrike, ID, strikeCount == 1 ? "a" : strikeCount.ToString(), strikeCount == 1 ? "" : "s", strikePenalty, userNickName, string.IsNullOrEmpty(StrikeMessage) ? "" : " caused by " + StrikeMessage); if (strikeCount <= 0) { return; } string recordMessageTone = $"Holdable ID: {ID} | Player: {userNickName} | Strike"; TwitchPlaySettings.AppendToSolveStrikeLog(recordMessageTone, TwitchPlaySettings.data.EnableRewardMultipleStrikes ? strikeCount : 1); int originalReward = TwitchPlaySettings.GetRewardBonus(); int currentReward = Convert.ToInt32(originalReward * (1 - (1 - TwitchPlaySettings.data.AwardDropMultiplierOnStrike) * OtherModes.ScoreMultiplier)); TwitchPlaySettings.AddRewardBonus(currentReward - originalReward); if (currentReward != originalReward) { IRCConnection.SendMessage($"Reward {(currentReward > 0 ? "reduced" : "increased")} to {currentReward} points."); } if (OtherModes.TimeModeOn) { bool multiDropped = OtherModes.DropMultiplier(); float multiplier = OtherModes.GetMultiplier(); string tempMessage = multiDropped ? "Multiplier reduced to " + Math.Round(multiplier, 1) + " and time" : $"Multiplier set at {TwitchPlaySettings.data.TimeModeMinMultiplier}, cannot be further reduced. Time"; if (bomb.CurrentTimer < (TwitchPlaySettings.data.TimeModeMinimumTimeLost / TwitchPlaySettings.data.TimeModeTimerStrikePenalty)) { bomb.Bomb.GetTimer().TimeRemaining = bomb.CurrentTimer - TwitchPlaySettings.data.TimeModeMinimumTimeLost; tempMessage += $" reduced by {TwitchPlaySettings.data.TimeModeMinimumTimeLost} seconds."; } else { float timeReducer = bomb.CurrentTimer * TwitchPlaySettings.data.TimeModeTimerStrikePenalty; double easyText = Math.Round(timeReducer, 1); bomb.Bomb.GetTimer().TimeRemaining = bomb.CurrentTimer - timeReducer; tempMessage += $" reduced by {Math.Round(TwitchPlaySettings.data.TimeModeTimerStrikePenalty * 100, 1)}%. ({easyText} seconds)"; } IRCConnection.SendMessage(tempMessage); bomb.StrikeCount = 0; if (TwitchGame.ModuleCameras != null) { TwitchGame.ModuleCameras.UpdateStrikes(); } } Leaderboard.Instance?.AddScore(userNickName, strikePenalty); Leaderboard.Instance?.AddStrike(userNickName, strikeCount); StrikeMessage = string.Empty; }
public static void CallCountCommand() => IRCConnection.SendMessageFormat("{0} out of {1} calls needed.", TwitchGame.Instance.CallingPlayers.Count, TwitchGame.Instance.callsNeeded);