public static void Help(TwitchModule module, [Group(1)] bool pdf) { string manualType = pdf ? "pdf" : "html"; string manualText = (Repository.GetManual(module.BombComponent.GetModuleID()) ?? module.BombComponent.GetModuleDisplayName()) + TranslatedModuleHelper.GetManualCodeAddOn(module.Solver.LanguageCode); string helpText = string.IsNullOrEmpty(module.Solver.HelpMessage) ? string.Empty : string.Format(module.Solver.HelpMessage, module.Code, module.HeaderText); IRCConnection.SendMessage($"{module.HeaderText} : {helpText} : {UrlHelper.ManualFor(manualText, manualType, VanillaRuleModifier.GetModuleRuleSeed(module.Solver.ModInfo.moduleID) != 1)}"); }
public static IEnumerator DefaultCommand(TwitchModule module, string user, string cmd) { if (cmd.RegexMatch(out Match match, @"(?<zoom>zoom *(?<time>\d*\.?\d+)?)? *(?<tilt>tilt *(?<direction>[uptobmdwnlefrigh]+|-?\d+)?)? *(?:send *to *module)? *(?<command>.+)?")) { var groups = match.Groups; var timed = groups["time"].Success; var zoom = groups["zoom"].Success; var tilt = groups["tilt"].Success; var command = groups["command"].Success; // Both a time and a command can't be entered. And either a zoom or tilt needs to take place otherwise, we should let the command run normally. if ((!timed || !command) && (zoom || tilt)) { MusicPlayer musicPlayer = null; int delay = 2; if (timed) { delay = groups["time"].Value.TryParseInt() ?? 2; delay = Math.Max(2, delay); if (delay >= 15) { musicPlayer = MusicPlayer.StartRandomMusic(); } } object toYield = command ? (object)RunModuleCommand(module, user, groups["command"].Value) : delay; IEnumerator routine = null; if (tilt) { routine = Tilt(module, toYield, groups["direction"].Value); } if (zoom) { routine = Zoom(module, user, routine ?? toYield); } yield return(routine); if (CoroutineCanceller.ShouldCancel) { CoroutineCanceller.ResetCancel(); IRCConnection.SendMessage($"Sorry @{user}, your request to hold up the bomb for {delay} seconds has been cut short."); } if (musicPlayer != null) { musicPlayer.StopMusic(); } yield break; } } yield return(RunModuleCommand(module, user, cmd)); }
public TwitchPlaysProperties() { AddProperty("TimeMode", new Property(() => OtherModes.TimeModeOn, x => OtherModes.TimeModeOn = (bool)x)); AddProperty("ZenMode", new Property(() => OtherModes.Unexplodable, x => OtherModes.ZenModeOn = (bool)x)); AddProperty("TimeModeTimeLimit", new Property(() => TwitchPlaySettings.data.TimeModeStartingTime, SetTimeModeTimeLimit)); AddProperty("ircConnectionSendMessage", new Property(null, x => IRCConnection.SendMessage((string)x))); AddProperty("Reward", new Property(() => TwitchPlaySettings.GetRewardBonus(), x => TwitchPlaySettings.SetRewardBonus((int)x))); AddProperty("CauseFakeStrike", new Property(null, CauseFakeStrike)); }
public static bool DefaultCommand(string cmd, string user, bool isWhisper) { if (TwitchPlaySettings.data.BombCustomMessages.ContainsKey(cmd.ToLowerInvariant())) { IRCConnection.SendMessage(TwitchPlaySettings.data.BombCustomMessages[cmd.ToLowerInvariant()], user, !isWhisper); return(true); } return(false); }
public static void SetNotesClear([Group(1)] int index, string user, bool isWhisper) { IRCConnection.SendMessage(string.Format(TwitchPlaySettings.data.NoteSlotCleared, index), user, !isWhisper); index--; if (TwitchGame.Instance.NotesDictionary.ContainsKey(index)) { TwitchGame.Instance.NotesDictionary.Remove(index); } TwitchGame.ModuleCameras?.SetNotes(); }
public MotionSenseComponentSolver(TwitchModule module) : base(module) { _component = module.BombComponent.GetComponent(ComponentType); _needy = (KMNeedyModule)NeedyField.GetValue(_component); ModInfo = ComponentSolverFactory.GetModuleInfo(GetModuleType(), "I am a passive module that awards strikes for motion while I am active. Use !{0} status to find out if I am active, and for how long."); _needy.OnNeedyActivation += () => IRCConnection.SendMessage($"Motion Sense just activated: Active for {(int) _needy.GetNeedyTimeRemaining()} seconds."); _needy.OnTimerExpired += () => IRCConnection.SendMessage("Motion Sense now Inactive."); }
public static void EndVoteEarly(string user) { if (!Active) { IRCConnection.SendMessage($"{user}, there is no vote currently in progress."); return; } IRCConnection.SendMessage("The vote is being ended now."); VoteTimeRemaining = 0f; }
public static void CancelVote(string user) { if (!Active) { IRCConnection.SendMessage($"{user}, there is no vote currently in progress."); return; } IRCConnection.SendMessage("The vote has been cancelled."); DestroyVote(); }
public static void EnqueueNamedCommand(string user, bool isWhisper, [Group(1)] string name, [Group(2)] string command) { if (name.Trim().EqualsIgnoreCase("all")) { IRCConnection.SendMessage(@"@{0}, you can’t use “all” as a name for queued commands.", user, !isWhisper, user); return; } TwitchGame.Instance.CommandQueue.Add(new CommandQueueItem(command, user, name.Trim())); TwitchGame.ModuleCameras?.SetNotes(); }
private static void ClaimViewOrPin(TwitchModule module, string user, bool isWhisper, bool view, bool pin) { if (isWhisper) { IRCConnection.SendMessage($"@{user}, claiming modules is not allowed in whispers.", user, false); return; } IRCConnection.SendMessage(module.TryClaim(user, view, pin).Message); }
public static void Help(TwitchModule module, [Group(1)] bool pdf) { string manualType = pdf ? "pdf" : "html"; string manualText = string.IsNullOrEmpty(module.Solver.ManualCode) ? module.HeaderText : module.Solver.ManualCode; string helpText = string.IsNullOrEmpty(module.Solver.HelpMessage) ? string.Empty : string.Format(module.Solver.HelpMessage, module.Code, module.HeaderText); IRCConnection.SendMessage(Regex.IsMatch(manualText, @"^https?://", RegexOptions.IgnoreCase) ? $"{module.HeaderText} : {helpText} : {manualText}" : $"{module.HeaderText} : {helpText} : {UrlHelper.Instance.ManualFor(manualText, manualType, VanillaRuleModifier.GetModuleRuleSeed(module.Solver.ModInfo.moduleID) != 1)}"); }
public static IEnumerator Run(string user, [Group(1)] string text) { if (!UserAccess.HasAccess(user, AccessLevel.Admin, true)) { if (!TwitchPlaySettings.data.EnableDMGForEveryone) { IRCConnection.SendMessage("Only admins can use the DMG."); yield break; } if (!OtherModes.TrainingModeOn) { IRCConnection.SendMessage("Only admins can use DMG when not in training mode."); yield break; } } var pageNavigation = UnityEngine.Object.FindObjectOfType(pageNavigationType); // pageNavigation could be null if this command is run multiple times in the setup room. if (pageNavigation == null) { yield break; } _backStack = pageNavigation.GetValue <Stack <KMSelectable> >("_backStack"); while (!CurrentPage.name.EqualsAny("PageOne(Clone)", "Home(Clone)")) { KTInputManager.Instance.HandleCancel(); yield return(new WaitForSeconds(0.1f)); } if (CurrentPage.name == "Home(Clone)") { var entryIndex = ReflectionHelper.FindType("PageManager") .GetValue <IList>("HomePageEntryList") .Cast <object>() .IndexOf(entry => entry.GetValue <string>("DisplayName") == "Dynamic Mission Generator"); if (entryIndex == -1) { IRCConnection.SendMessage("DMG is not installed."); yield break; } CurrentPage.Children[entryIndex].OnInteract(); yield return(new WaitForSeconds(0.1f)); } CurrentPage.gameObject.Traverse <InputField>("Canvas", "InputField").text = text; yield return(new WaitForSeconds(0.1f)); CurrentPage.Children.First(button => button.name.Contains("Run")).OnInteract(); }
public static void EnqueueNamedCommand(IRCMessage msg, [Group(1)] string name, [Group(2)] string command) { if (name.Trim().EqualsIgnoreCase("all")) { IRCConnection.SendMessage(@"@{0}, you can’t use “all” as a name for queued commands.", msg.UserNickName, !msg.IsWhisper, msg.UserNickName); return; } TwitchGame.Instance.CommandQueue.Add(new CommandQueueItem(msg.Duplicate(command), name.Trim())); TwitchGame.ModuleCameras?.SetNotes(); IRCConnection.SendMessage("@{0}, command queued.", msg.UserNickName, !msg.IsWhisper, msg.UserNickName); }
protected override IEnumerator RespondToCommandInternal(string inputCommand) { if (!inputCommand.Equals("status", StringComparison.InvariantCultureIgnoreCase)) { yield break; } bool active = (bool)_activeField.GetValue(_component); _connection.SendMessage("Motion Sense Status: " + (active ? "Active for " + (int)_needy.GetNeedyTimeRemaining() + " seconds" : "Inactive")); }
public static void FindDuplicate([Group(1)] string queries, string user, bool isWhisper) { var allMatches = (string.IsNullOrEmpty(queries) ? TwitchGame.Instance.Modules : FindModules(queries.SplitFull(',', ';').Select(q => q.Trim()).Distinct().ToArray())) .GroupBy(module => module.HeaderText) .Where(grouping => grouping.Count() > 1) .Select(grouping => $"{grouping.Key} ({grouping.Select(module => module.Code).Join(", ")})"); var modules = allMatches.Shuffle().Take(3).ToList(); IRCConnection.SendMessage(modules.Count > 0 ? $"Duplicates ({allMatches.Count()} total): {modules.Join(", ")}" : "No such duplicate modules.", user, !isWhisper); }
public bool IsAuthorizedDefuser(string userNickName, bool silent = false) { bool result = (TwitchPlaySettings.data.EnableTwitchPlaysMode || UserAccess.HasAccess(userNickName, AccessLevel.Defuser, true)); if (!result && !silent) { _ircConnection.SendMessage(TwitchPlaySettings.data.TwitchPlaysDisabled, userNickName); } return(result); }
public static void DisableCameraWall(string user) { if (TwitchPlaySettings.data.EnableAutomaticCameraWall && !UserAccess.HasAccess(user, AccessLevel.Admin, true)) { IRCConnection.SendMessage("The camera wall is being controlled automatically and cannot be disabled."); } else { TwitchGame.ModuleCameras.DisableCameraWall(); } }
public static void ShowClaims(string user, bool isWhisper) { if (TwitchPlaySettings.data.AnarchyMode) { IRCConnection.SendMessage($"Sorry {user}, claiming modules is not available in anarchy mode.", user, !isWhisper); } else { ShowClaimsOfUser(user, user, isWhisper, TwitchPlaySettings.data.OwnedModuleList, TwitchPlaySettings.data.NoOwnedModules); } }
public static bool IsAuthorizedDefuser(string userNickName, bool isWhisper, bool silent = false) { if (userNickName.EqualsAny("Bomb Factory", TwitchPlaySettings.data.TwitchPlaysDebugUsername) || TwitchGame.Instance.Bombs.Any(x => x.BombName == userNickName)) { return(true); } BanData ban = UserAccess.IsBanned(userNickName); if (ban != null) { if (silent) { return(false); } if (double.IsPositiveInfinity(ban.BanExpiry)) { IRCConnection.SendMessage($"Sorry @{userNickName}, You were banned permanently from Twitch Plays by {ban.BannedBy}{(string.IsNullOrEmpty(ban.BannedReason) ? "." : $", for the following reason: {ban.BannedReason}")}", userNickName, !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 @{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}", userNickName, !isWhisper); } return(false); } bool result = (TwitchPlaySettings.data.EnableTwitchPlaysMode || UserAccess.HasAccess(userNickName, AccessLevel.Defuser, true)); if (!result && !silent) { IRCConnection.SendMessage(string.Format(TwitchPlaySettings.data.TwitchPlaysDisabled, userNickName), userNickName, !isWhisper); } return(result); }
public static IEnumerator Edgework(TwitchBomb bomb, [Group(1)] string edge, string user, bool isWhisper) { if (TwitchPlaySettings.data.EnableEdgeworkCommand || TwitchPlaySettings.data.AnarchyMode) { return(bomb.ShowEdgework(edge)); } else { IRCConnection.SendMessage(string.Format(TwitchPlaySettings.data.BombEdgework, bomb.EdgeworkText.text), user, !isWhisper); return(null); } }
protected void HandleModuleException(Exception e) { Debug.Log("[TwitchPlays] While solving a module an exception has occurred! Here's the error:"); Debug.LogException(e); IRCConnection.SendMessage("Looks like a module ran into a problem while running a command, automatically solving module. Some other modules may also be solved to prevent problems."); _currentUserNickName = null; _delegatedSolveUserNickName = null; BombCommander.RemoveSolveBasedModules(); CommonReflectedTypeInfo.HandlePassMethod.Invoke(BombComponent, null); }
public static void ListUnclaimed(string user, bool isWhisper) { IEnumerable <string> unclaimed = TwitchGame.Instance.Modules .Where(handle => !handle.Claimed && !handle.Solved) .Shuffle().Take(3) .Select(handle => string.Format($"{handle.HeaderText} ({handle.Code})")) .ToList(); IRCConnection.SendMessage(unclaimed.Any() ? $"Unclaimed Modules: {unclaimed.Join(", ")}" : string.Format(TwitchPlaySettings.data.NoUnclaimed, user), user, !isWhisper); }
public static void ClaimSpecific(string user, bool isWhisper, [Group(1)] bool view1, [Group(2)] bool view2, [Group(3)] string claimWhat) { var strings = claimWhat.Split(new[] { ' ', ',', ';' }, StringSplitOptions.RemoveEmptyEntries); var modules = strings.Length == 0 ? null : TwitchGame.Instance.Modules.Where(md => strings.Any(str => str.EqualsIgnoreCase(md.Code))).ToArray(); if (modules == null || modules.Length == 0) { IRCConnection.SendMessage($"{user}: no such module.", user, !isWhisper); return; } Claim(user, isWhisper, view1 || view2, modules); }
private static IEnumerator VotingCoroutine() { int oldTime; while (VoteTimeRemaining >= 0f) { oldTime = TimeLeft; VoteTimeRemaining -= Time.deltaTime; if (TwitchGame.BombActive && TimeLeft != oldTime) // Once a second, update notes. { TwitchGame.ModuleCameras.SetNotes(); } yield return(null); } if (TwitchGame.BombActive && CurrentVoteType == VoteTypes.Detonation) { // Add claimed users who didn't vote as "no" int numAddedNoVotes = 0; List <string> usersWithClaims = TwitchGame.Instance.Modules .Where(m => !m.Solved && m.PlayerName != null).Select(m => m.PlayerName).Distinct().ToList(); foreach (string user in usersWithClaims) { if (!Voters.ContainsKey(user)) { ++numAddedNoVotes; Voters.Add(user, false); } } if (numAddedNoVotes == 1) { IRCConnection.SendMessage("1 no vote was added on the behalf of users with claims that did not vote."); } else if (numAddedNoVotes > 1) { IRCConnection.SendMessage($"{numAddedNoVotes} no votes were added on the behalf of users with claims that did not vote."); } } int yesVotes = Voters.Count(pair => pair.Value); bool votePassed = (yesVotes >= Voters.Count * (TwitchPlaySettings.data.MinimumYesVotes[CurrentVoteType] / 100f)); IRCConnection.SendMessage($"Voting has ended with {yesVotes}/{Voters.Count} yes votes. The vote has {(votePassed ? "passed" : "failed")}."); if (votePassed) { PossibleVotes[CurrentVoteType].onSuccess(); } DestroyVote(); }
protected void SolveModule(string reason = "A module is being automatically solved.", bool removeSolveBasedModules = true) { IRCConnection.SendMessage("{0}{1}", reason, removeSolveBasedModules ? " Some other modules may also be solved to prevent problems." : ""); _currentUserNickName = null; _delegatedSolveUserNickName = null; if (removeSolveBasedModules) { TwitchComponentHandle.RemoveSolveBasedModules(); } CommonReflectedTypeInfo.HandlePassMethod.Invoke(BombComponent, null); }
public static IEnumerator Retry(string user, bool isWhisper) { if (!TwitchPlaySettings.data.EnableRetryButton) { IRCConnection.SendMessage(TwitchPlaySettings.data.RetryInactive, user, isWhisper); return(doButton(Object.FindObjectOfType <ResultPage>().ContinueButton)); } else { TwitchPlaySettings.SetRetryReward(); return(doButton(Object.FindObjectOfType <ResultPage>().RetryButton)); } }
public static void LogException(Exception ex, string message = "An exception has occurred:") { Log(message); Debug.LogException(ex); // Avoid spamming this message in chat by only posting it at most once every 5 minutes. if (Time.time - lastException >= 5 * 60) { IRCConnection.SendMessage("Something has caused an exception to occur. Please report this to the TP developers and include the logfile for more information."); } lastException = Time.time; }
public static void ChangeTimer(TwitchBomb bomb, string user, bool isWhisper, [Group(1)] bool negative, [Group(2)] bool direct, [Group(3)] string amount) { float time = 0; float originalTime = bomb.Bomb.GetTimer().TimeRemaining; var timeLengths = new Dictionary <string, float>() { { "ms", 0.001f }, { "s", 1 }, { "m", 60 }, { "h", 3600 }, { "d", 86400 }, { "w", 604800 }, { "y", 31536000 }, }; foreach (string part in amount.Split(new[] { ' ', ',', ';' }, StringSplitOptions.RemoveEmptyEntries)) { bool valid = false; foreach (string unit in timeLengths.Keys) { if (!part.EndsWith(unit, StringComparison.InvariantCultureIgnoreCase) || !float.TryParse(part.Substring(0, part.Length - unit.Length), out float length)) { continue; } time += length * timeLengths[unit]; valid = true; break; } if (!valid) { IRCConnection.SendMessage(@"I don’t understand “{0}”.", user, !isWhisper, part); return; } } time = (float)Math.Round((decimal)time, 2, MidpointRounding.AwayFromZero); if (!direct && Math.Abs(time) < 0.01f) { return; } bomb.CurrentTimer = direct ? time : negative ? bomb.CurrentTimer - time : bomb.CurrentTimer + time; // If the time requested was negative, we need to flip the message. bool negativeTime = time < 0 ? !negative : negative; IRCConnection.SendMessage(direct ? $"Set the bomb's timer to {Math.Abs(time < 0 ? 0 : time).FormatTime()}." : $"{(negativeTime ? "Subtracted" : "Added")} {Math.Abs(time).FormatTime()} {(negativeTime ? "from" : "to")} the timer.", user, !isWhisper); }
public static void SetNotesAppend([Group(1)] int index, [Group(2)] string notes, string user, bool isWhisper) { IRCConnection.SendMessage(string.Format(TwitchPlaySettings.data.NotesAppended, index, notes), user, !isWhisper); index--; if (TwitchGame.Instance.NotesDictionary.ContainsKey(index)) { TwitchGame.Instance.NotesDictionary[index] += " " + notes; } else { TwitchGame.Instance.NotesDictionary[index] = notes; } TwitchGame.ModuleCameras?.AppendNotes(index, notes); }
public static void ShowClaimsOfAnotherPlayer([Group(1)] string targetUser, string user, bool isWhisper) { if (TwitchPlaySettings.data.AnarchyMode) { IRCConnection.SendMessage($"Sorry {user}, claiming modules is not available in anarchy mode.", user, !isWhisper); } else if (isWhisper && TwitchPlaySettings.data.EnableWhispers) { IRCConnection.SendMessage("Checking other people's claims in whispers is not supported.", user, false); } else { ShowClaimsOfUser(targetUser, user, isWhisper, TwitchPlaySettings.data.OwnedModuleListOther, TwitchPlaySettings.data.NoOwnedModulesOther); } }