private static void SetSetting(FloatingHoldable holdable, bool on, string user, bool isWhisper, Func <FreeplaySettings, bool> getCurrent, Func <FreeplayDevice, ToggleSwitch> toggle, bool settingAllowed, string disabledMessage)
 {
     if (settingAllowed || !on || UserAccess.HasAccess(user, AccessLevel.Admin, true) || TwitchPlaySettings.data.AnarchyMode)
     {
         var device = holdable.GetComponent <FreeplayDevice>();
         if (on != getCurrent(device.CurrentSettings))
         {
             toggle(device).GetComponent <Selectable>().Trigger();
         }
     }
     else
     {
         IRCConnection.SendMessage(string.Format(disabledMessage, user), user, !isWhisper);
     }
 }
    public IEnumerator Focus(Selectable selectable, float focusDistance, bool frontFace)
    {
        IEnumerator holdCoroutine = HoldBomb(frontFace);

        while (holdCoroutine.MoveNext())
        {
            yield return(holdCoroutine.Current);
        }

        float focusTime = FloatingHoldable.FocusTime;

        FloatingHoldable.Focus(selectable.transform, focusDistance, false, false, focusTime);
        selectable.HandleSelect(false);
        selectable.HandleInteract();
    }
示例#3
0
        /// <summary>
        /// Unity event.
        /// </summary>
        private void Awake()
        {
            Ended = false;

            InternalBomb    = GetComponent <Bomb>();
            Timer           = InternalBomb.GetTimer();
            _holdable       = GetComponentInChildren <FloatingHoldable>();
            _selectableArea = GetComponentInChildren <SelectableArea>();
            Selectable      = GetComponent <Selectable>();

            ChangeTimerVisibility(false);
            SetSelectableLayer(false);

            BombEvents.OnBombSolved    += OnAnyBombSolved;
            BombEvents.OnBombDetonated += OnAnyBombDetonated;
        }
    protected HoldableHandler(KMHoldableCommander commander, FloatingHoldable holdable)
    {
        HoldableCommander = commander;
        Holdable          = holdable;

        if (!BombMessageResponder.BombActive)
        {
            return;
        }
        KMGameCommands gameCommands = holdable.GetComponent <KMGameCommands>();

        if (gameCommands == null)
        {
            return;
        }
        gameCommands.OnCauseStrike += OnStrike;
    }
示例#5
0
    public static IEnumerator Throw(FloatingHoldable holdable, [Group(1)] int?optionalStrength = 3)
    {
        int strength = optionalStrength ?? 3;

        holdable.Pause();
        Rigidbody rigidbody = holdable.GetComponent <Rigidbody>();

        rigidbody.isKinematic        = false;
        rigidbody.useGravity         = true;
        rigidbody.velocity           = Random.onUnitSphere * rigidbody.mass * strength;
        rigidbody.angularVelocity    = Random.onUnitSphere * rigidbody.mass * strength;
        rigidbody.maxAngularVelocity = 100f;
        yield return(new WaitForSeconds(2));

        rigidbody.isKinematic = true;
        rigidbody.useGravity  = false;
        holdable.Resume();
    }
示例#6
0
    public static IEnumerator ChangeModuleCount(FloatingHoldable holdable, [Group(1)] int moduleCount)
    {
        var device             = holdable.GetComponent <FreeplayDevice>();
        int currentModuleCount = device.CurrentSettings.ModuleCount;
        var button             = (moduleCount > currentModuleCount ? device.ModuleCountIncrement : device.ModuleCountDecrement).GetComponent <Selectable>();

        for (int hitCount = 0; hitCount < Mathf.Abs(moduleCount - currentModuleCount); ++hitCount)
        {
            int lastModuleCount = device.CurrentSettings.ModuleCount;
            button.Trigger();
            yield return(new WaitForSeconds(0.01f));

            if (lastModuleCount == device.CurrentSettings.ModuleCount)
            {
                yield break;
            }
        }
    }
    public IEnumerator LetGoBomb()
    {
        if (FloatingHoldable.GetComponent <FloatingHoldable>().HoldState != global::FloatingHoldable.HoldStateEnum.Held)
        {
            yield break;
        }

        IEnumerator turnCoroutine = Hold(true);

        while (turnCoroutine.MoveNext())
        {
            yield return(turnCoroutine.Current);
        }

        while (FloatingHoldable.GetComponent <FloatingHoldable>().HoldState == global::FloatingHoldable.HoldStateEnum.Held)
        {
            DeselectObject(Selectable.GetComponent <Selectable>());
            yield return(new WaitForSeconds(0.1f));
        }
    }
示例#8
0
    private static IEnumerator SetBombTimer(FloatingHoldable holdable, int hours, int minutes, int seconds)
    {
        if (seconds >= 60)
        {
            yield break;
        }

        var device    = holdable.GetComponent <FreeplayDevice>();
        int timeIndex = (hours * 120) + (minutes * 2) + (seconds / 30);

        DebugHelper.Log("Freeplay time doubling section");
        //Double the available free play time. (The doubling stacks with the Multiple bombs module installed)
        float originalMaxTime = FreeplayDevice.MAX_SECONDS_TO_SOLVE;
        int   maxModules      = (int)_maxModuleField.GetValue(device);
        int   multiplier      = MultipleBombs.Installed() ? (MultipleBombs.GetMaximumBombCount() * 2) - 1 : 1;
        float newMaxTime      = 600f + (maxModules - 1) * multiplier * 60;

        FreeplayDevice.MAX_SECONDS_TO_SOLVE = newMaxTime;

        DebugHelper.Log("Freeplay settings reading section");
        float        currentTime      = device.CurrentSettings.Time;
        int          currentTimeIndex = Mathf.FloorToInt(currentTime) / 30;
        KeypadButton button           = timeIndex > currentTimeIndex ? device.TimeIncrement : device.TimeDecrement;
        Selectable   buttonSelectable = button.GetComponent <Selectable>();

        DebugHelper.Log("Freeplay time setting section");
        for (int hitCount = 0; hitCount < Mathf.Abs(timeIndex - currentTimeIndex); ++hitCount)
        {
            currentTime = device.CurrentSettings.Time;
            buttonSelectable.Trigger();
            yield return(new WaitForSeconds(0.01f));

            if (Mathf.FloorToInt(currentTime) == Mathf.FloorToInt(device.CurrentSettings.Time))
            {
                break;
            }
        }

        //Restore original max time, just in case Multiple bombs module was NOT installed, to avoid false detection.
        FreeplayDevice.MAX_SECONDS_TO_SOLVE = originalMaxTime;
    }
示例#9
0
    public static HoldableHandler CreateHandler(KMHoldableCommander commander, FloatingHoldable holdable)
    {
        if (commander != null)
        {
            commander.ID = holdable.name.ToLowerInvariant().Replace("(clone)", "");
        }

        foreach (Type type in ModHoldableTypes)
        {
            if (type?.FullName == null)
            {
                continue;
            }
            if (holdable.GetComponent(type) == null || !ModHoldableCreators.ContainsKey(type.FullName))
            {
                continue;
            }
            return(ModHoldableCreators[type.FullName](commander, holdable));
        }

        return(CreateModComponentSolver(commander, holdable));
    }
示例#10
0
    public IEnumerator Defocus(Selectable selectable, bool frontFace)
    {
        IEnumerator gameRoomDefocus    = GameRoom.Instance?.BombCommanderDefocus(Bomb, selectable, frontFace);
        bool        continueInvocation = true;

        if (gameRoomDefocus != null && gameRoomDefocus.MoveNext() && gameRoomDefocus.Current is bool continueInvoke)
        {
            continueInvocation = continueInvoke;
            do
            {
                yield return(gameRoomDefocus.Current);
            } while (gameRoomDefocus.MoveNext());
        }

        if (!continueInvocation || FloatingHoldable == null)
        {
            yield break;
        }

        FloatingHoldable.Defocus(false, false);
        selectable.HandleCancel();
        selectable.HandleDeselect();
    }
示例#11
0
    public static IEnumerator ChangeBombCount(FloatingHoldable holdable, [Group(1)] int bombCount)
    {
        if (!MultipleBombs.Installed())
        {
            yield break;
        }

        int currentBombCount = MultipleBombs.GetFreePlayBombCount();
        var buttonSelectable = holdable.GetComponent <Selectable>().Children[bombCount > currentBombCount ? 3 : 2];

        for (int hitCount = 0; hitCount < Mathf.Abs(bombCount - currentBombCount); ++hitCount)
        {
            int lastBombCount = MultipleBombs.GetFreePlayBombCount();
            buttonSelectable.Trigger();
            yield return(new WaitForSeconds(0.01f));

            // Stop here if we hit a maximum or minimum
            if (lastBombCount == MultipleBombs.GetFreePlayBombCount())
            {
                yield break;
            }
        }
    }
示例#12
0
 public static void Start(FloatingHoldable holdable) => holdable.GetComponent <FreeplayDevice>().StartButton.GetComponent <Selectable>().Trigger();
示例#13
0
 private static bool FindCancelBool(FloatingHoldable holdable, Type holdableType, out FieldInfo CancelField)
 {
     CancelField = holdableType.GetField("TwitchShouldCancelCommand", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
     return(CancelField?.GetValue(holdable.GetComponent(holdableType)) is bool);
 }
示例#14
0
 public static IEnumerator ChangeTimer(FloatingHoldable holdable, [Group(1)] int minutes, [Group(2)] int seconds) => SetBombTimer(holdable, 0, minutes, seconds);
示例#15
0
 public static void ModsOnly(FloatingHoldable holdable, [Group(1)] bool on, string user, bool isWhisper) => SetSetting(holdable, on, user, isWhisper, s => s.OnlyMods, s => s.ModsOnly, TwitchPlaySettings.data.EnableFreeplayModsOnly, TwitchPlaySettings.data.FreePlayModsOnlyDisabled);
示例#16
0
 public static void Hardcore(FloatingHoldable holdable, [Group(1)] bool on, string user, bool isWhisper) => SetSetting(holdable, on, user, isWhisper, s => s.IsHardCore, s => s.HardcoreToggle, TwitchPlaySettings.data.EnableFreeplayHardcore, TwitchPlaySettings.data.FreePlayHardcoreDisabled);
示例#17
0
 public static void Needy(FloatingHoldable holdable, [Group(1)] bool on, string user, bool isWhisper) => SetSetting(holdable, on, user, isWhisper, s => s.HasNeedy, s => s.NeedyToggle, TwitchPlaySettings.data.EnableFreeplayNeedy, TwitchPlaySettings.data.FreePlayNeedyDisabled);
 public UnsupportedHoldableHandler(KMHoldableCommander commander, FloatingHoldable holdable)
     : base(commander, holdable)
 {
     HelpMessage = "!{0} is not supported by Twitch Plays yet.";
 }
示例#19
0
 /// <summary>Adds a holdable, ensuring that the ID in <see cref="Holdables"/> is the same as the one in it's <see cref="TwitchHoldable"/>.</summary>
 private void AddHoldable(string id, FloatingHoldable holdable, Type commandType = null, bool allowModded = false)
 {
     Holdables[id] = new TwitchHoldable(holdable, commandType, allowModded, id);
 }
示例#20
0
 public static IEnumerator SelectSearch(FloatingHoldable holdable, [Group(1)] string search) => SelectOnPage(holdable, search: search.Split(new[] { ' ', ',', ';' }, StringSplitOptions.RemoveEmptyEntries));
示例#21
0
 public static IEnumerator SelectIndex(FloatingHoldable holdable, [Group(1)] int index) => SelectOnPage(holdable, index: index);
示例#22
0
 public static IEnumerator Select(FloatingHoldable holdable) => SelectOnPage(holdable);
示例#23
0
    private static IEnumerator SelectOnPage(FloatingHoldable holdable, int index = 0, IList <string> search = null)
    {
        if (TwitchPlaysService.Instance.CurrentState != KMGameInfo.State.Setup)
        {
            yield break;
        }

        if (index > 0 || (search != null && search.Count > 0))
        {
            if ((_currentSelectables == null) || (index > _currentSelectables.Length))
            {
                yield break;
            }

            int oldSelectableIndex = _currentSelectableIndex;

            int        i             = 0;
            Selectable newSelectable = null;
            for (_currentSelectableIndex = 0; _currentSelectableIndex < _currentSelectables.Length; ++_currentSelectableIndex)
            {
                if (_currentSelectables[_currentSelectableIndex] == null)
                {
                    continue;
                }

                // Index mode
                if (index > 0)
                {
                    if (++i == index)
                    {
                        newSelectable = _currentSelectables[_currentSelectableIndex];
                        break;
                    }
                }
                // Search mode
                else
                {
                    var mission = _currentSelectables[_currentSelectableIndex].GetComponent <MissionTableOfContentsMissionEntry>();

                    if (mission == null)
                    {
                        continue;
                    }

                    string missionName = mission.EntryText.text.ToLowerInvariant();

                    // Trigger the mission if EITHER
                    // • the first search term matches the mission ID (e.g., "2.1"); OR
                    // • all search terms are found in the mission name
                    if (mission.SubsectionText.text.Equals(search?[0], StringComparison.InvariantCultureIgnoreCase) || search.All(s => missionName.ContainsIgnoreCase(s)))
                    {
                        newSelectable = _currentSelectables[_currentSelectableIndex];
                        break;
                    }
                }
            }

            if (newSelectable == null)
            {
                _currentSelectableIndex = oldSelectableIndex;
                yield break;
            }

            _currentSelectable.HandleDeselect();
            _currentSelectable = newSelectable;
        }

        if (_currentSelectable == null)
        {
            yield break;
        }

        _currentSelectable.HandleSelect(true);
        KTInputManager.Instance.SelectableManager.Select(_currentSelectable, true);

        // Prevent users from trying to start the tutorial missions, assuming they actually selected a mission.
        var selectedMission = _currentSelectable.GetComponent <MissionTableOfContentsMissionEntry>();

        if (selectedMission != null && MissionManager.Instance.GetMission(selectedMission.MissionID).IsTutorial)
        {
            Audio.PlaySound(KMSoundOverride.SoundEffect.Strike, _currentSelectable.transform);
            IRCConnection.SendMessage("The tutorial missions are currently unsupported and cannot be selected.");
            yield break;
        }

        KTInputManager.Instance.SelectableManager.HandleInteract();
        _currentSelectable.OnInteractEnded();

        yield return(null);

        InitializePage(holdable);
    }
示例#24
0
    private static IEnumerator SelectOnPage(FloatingHoldable holdable, int index = 0)
    {
        if (TwitchPlaysService.Instance.CurrentState != KMGameInfo.State.Gameplay)
        {
            yield break;
        }

        if (index > 0)
        {
            if ((_currentSelectables == null) || (index > _currentSelectables.Length))
            {
                yield break;
            }

            int oldSelectableIndex = _currentSelectableIndex;

            int        i             = 0;
            Selectable newSelectable = null;
            for (_currentSelectableIndex = 0; _currentSelectableIndex < _currentSelectables.Length; ++_currentSelectableIndex)
            {
                if (_currentSelectables[_currentSelectableIndex] == null)
                {
                    continue;
                }

                // Index mode
                if (++i == index)
                {
                    newSelectable = _currentSelectables[_currentSelectableIndex];
                    break;
                }
            }

            if (newSelectable == null)
            {
                _currentSelectableIndex = oldSelectableIndex;
                yield break;
            }

            _currentSelectable.HandleDeselect();
            _currentSelectable = newSelectable;
        }

        if (_currentSelectable == null)
        {
            yield break;
        }

        _currentSelectable.HandleSelect(true);
        KTInputManager.Instance.SelectableManager.Select(_currentSelectable, true);

        // Prevent users from trying to select anything that is not the dossier modifier button
        if (!_currentSelectable.name.StartsWith("SolveDossierModifier"))
        {
            Audio.PlaySound(KMSoundOverride.SoundEffect.Strike, _currentSelectable.transform);
            IRCConnection.SendMessage("This option is not accessable to Twitch Plays users.");
            yield break;
        }

        KTInputManager.Instance.SelectableManager.HandleInteract();
        _currentSelectable.OnInteractEnded();

        yield return(null);

        InitializePage(holdable);
    }
示例#25
0
    public static IEnumerator Search(FloatingHoldable holdable, [Group(1)] string query)
    {
        BombBinder binder      = SceneManager.Instance.SetupState.Room.GetComponent <SetupRoom>().BombBinder;
        var        pageManager = binder.MissionTableOfContentsPageManager;

        var possibleMissions = ModManager.Instance.ModMissions
                               .Concat(MissionManager.Instance.MissionDB.Missions)
                               .Where(mission => Localization.GetLocalizedString(mission.DisplayNameTerm)?.ContainsIgnoreCase(query) == true);

        switch (possibleMissions.Count())
        {
        case 0:
            IRCConnection.SendMessage($"There are no missions that match \"{query}\".");
            break;

        case 1:
            var missionID = possibleMissions.First().ID;
            binder.ShowMissionDetail(missionID, binder.MissionTableOfContentsPageManager.GetMissionEntry(missionID).Selectable);
            pageManager.FindMissionInBinder(missionID, out int tocIndex, out int pageIndex, out _);
            pageManager.SetValue("currentToCIndex", tocIndex);
            pageManager.SetValue("currentPageIndex", pageIndex);
            yield return(null);

            break;

        default:
            IRCConnection.SendMessage($"{possibleMissions.Count()} missions match \"{query}\", displaying matching missions in the binder.");

            var tableOfContentsList = pageManager.GetValue <List <MissionTableOfContents> >("tableOfContentsList");

            var previousResults = pageManager.GetToC("toc_tp_search");
            if (previousResults != null)
            {
                previousResults.ClearPages();
                tableOfContentsList.Remove(previousResults);
            }

            var missionIDs = possibleMissions.Select(mission => mission.ID);
            var metaData   = new TableOfContentsMetaData
            {
                ID       = "toc_tp_search",
                Sections = tableOfContentsList
                           .SelectMany(toc => toc.GetValue <TableOfContentsMetaData>("tocData").Sections)
                           .Where(section => missionIDs.Any(section.MissionIDs.Contains))
                           .Select(section => new SectionMetaData
                {
                    SectionNum = section.SectionNum,
                    TitleTerm  = section.TitleTerm,
                    MissionIDs = missionIDs.Where(section.MissionIDs.Contains).ToList(),
                    IsUnlocked = section.IsUnlocked
                })
                           .ToList()
            };

            MissionTableOfContents missionTableOfContents = new MissionTableOfContents();
            missionTableOfContents.Init(pageManager, metaData, binder.Selectable, true);
            tableOfContentsList.Add(missionTableOfContents);

            pageManager.ShowToC("toc_tp_search");

            yield return(null);

            break;
        }

        InitializePage(holdable);
    }
示例#26
0
    private static HoldableHandler CreateModComponentSolver(KMHoldableCommander commander, FloatingHoldable holdable)
    {
        DebugLog("Attempting to find a valid process command method to respond with on holdable {0}...", holdable.name);

        ModHoldableHandlerDelegate modComponentSolverCreator = GenerateModComponentSolverCreator(holdable, out Type holdableType);

        if (holdableType?.FullName == null || modComponentSolverCreator == null)
        {
            return(new UnsupportedHoldableHandler(commander, holdable));
        }

        ModHoldableCreators[holdableType.FullName] = modComponentSolverCreator;

        return(ModHoldableCreators[holdableType.FullName](commander, holdable));
    }