private void UpdateDisplay(bool updateLED = true, bool UpdateCharacter = true, bool UpdateInventory = true, bool forceUpdate = false)
    {
        if (!_NO_SIMULATION_RUNNING && !forceUpdate)
        {
            return;
        }
        if (UpdateCharacter)
        {
            CharacterText.text  = _character.Name;
            CharacterText.color = _colorValues[(int)_season];
            if (updateLED)
            {
                OffLED.SetActive(!_spellBonus);
                OnLED.SetActive(_spellBonus);
            }
        }
        if (UpdateInventory)
        {
            InventoryText.text = _inventory[_currentInventoryItem].Item;
        }
        StageNumberText.text = string.Format("{0}", _losses + 1);

        IncidentSet incident = new IncidentSet();

        if ((int)_incident < _incidedentSets.Count && (int)_incident >= 0)
        {
            incident = _incidedentSets[(int)_incident];
        }
        IncidentText.text = incident.Name;
    }
    private void PrintIncident(IncidentSet incident, bool boss1, bool bossbonus, out int distance, out int range)
    {
        if (incident == null)
        {
            distance = 0;
            range    = 0;
            return;
        }
        Boss boss = boss1 ? incident.Boss1 : incident.Boss2;

        if (boss == null)
        {
            distance = 0;
            range    = 0;
            return;
        }
        distance = boss.BaseDistance + boss.EdgeworkBonusDistance;
        range    = boss.BaseRange + boss.EdgeworkBonusRange;
        if (bossbonus)
        {
            distance += boss.BonusDistance;
            range    += boss.BonusRange;
        }

        if (_widgetbonus)
        {
            distance += boss.WidgetBonusDistance;
            range    += boss.WidgetBonusRange;
        }

        if (!_NO_SIMULATION_RUNNING)
        {
            return;
        }

        BombModule.LogFormat("Fighting {0} - Distance = {1}, Range = {2}", boss.Name, boss.BaseDistance, boss.BaseRange);
        if (bossbonus)
        {
            PrintBonus(boss.BonusDistance, boss.BonusRange, incident.BonusReason);
        }
        PrintBonus(boss.EdgeworkBonusDistance, boss.EdgeworkBonusRange, incident.EdgeworkBonusReason);
        if (_widgetbonus)
        {
            PrintBonus(boss.WidgetBonusDistance, boss.WidgetBonusRange, incident.WidgetBonusReason);
        }
    }
    void ReportWinResults(int BossBuff, bool printBuffInfo)
    {
        if (_WINSBOSS1 > 0 || _LOSSESBOSS1 > 0)
        {
            IncidentResults[_incident][0]++;
            IncidentResults[_incident][1] += _WINSBOSS1;
            IncidentResults[_incident][2] += _LOSSESBOSS1;
        }
        if (_WINSBOSS2 > 0 || _LOSSESBOSS2 > 0)
        {
            IncidentResults[_incident][3]++;
            IncidentResults[_incident][4] += _WINSBOSS2;
            IncidentResults[_incident][5] += _LOSSESBOSS2;
        }

        IncidentSet incident = _incidedentSets[(int)_incident];

        if (printBuffInfo)
        {
            BombModule.LogFormat("results with {0}/{0} Dist/Range {1}:", BossBuff, (BossBuff < 0 ? "penalty" : (BossBuff > 0 ? "bonus" : "bonus/penalty")));
        }
        if (_WINSBOSS1 > 0 || _LOSSESBOSS1 > 0)
        {
            BombModule.LogFormat("Boss #1 ({0}): W/L: {1}/{2}", incident.Boss1.Name, _WINSBOSS1, _LOSSESBOSS1);
        }

        if (_WINSBOSS2 > 0 || _LOSSESBOSS2 > 0)
        {
            BombModule.LogFormat("Boss #2 ({0}): W/L: {1}/{2}", incident.Boss2.Name, _WINSBOSS2, _LOSSESBOSS2);
        }



        _WINSBOSS1   = 0;
        _LOSSESBOSS1 = 0;
        _WINSBOSS2   = 0;
        _LOSSESBOSS2 = 0;
    }
    private void Initialize(int BossBuff, bool TwoFactorUpdate)
    {
        if (_solved)
        {
            return;
        }

        int         BossDistance;
        int         BossRange;
        IncidentSet incident = new IncidentSet {
            Name = "Error"
        };

        if ((int)_incident < _incidedentSets.Count && (int)_incident >= 0)
        {
            incident = _incidedentSets[(int)_incident];
        }
        bool boss1     = true;
        bool bossbonus = false;

        if (!TwoFactorUpdate)
        {
            RandomizeCharacter();
            RandomizeInventory();
            if (_NO_SIMULATION_RUNNING)
            {
                UpdateDisplay();
                BombModule.LogFormat("Resolving Incident: {0}", incident.Name);
            }
        }
        else
        {
            if (_NO_SIMULATION_RUNNING)
            {
                UpdateDisplay();
                BombModule.LogFormat("Updating Incident {0} results based on a change in the Two Factor sum", incident.Name);
            }
        }

        bool Strikes = false;

OddStrikes:
        if (_incident == Incidents.WorldlyDesires)
        {
            NoSimulationLog(!Strikes ? "Calculating the results for Even number of Strikes" : "Calculating the results for Odd number of Strikes");
        }

        int CharacterDistance = _characterBaseDistance;
        int CharacterRange    = _characterBaseRange;

        NoSimulationLog("Chararcter: {0} - Distance = {1}, Range = {2}, Season = {3}", _character.Name, CharacterDistance, CharacterRange, _season);

        if (_character.Heroine)
        {
            CharacterDistance++;
            CharacterRange++;
            NoSimulationLog("Character is a Heroine, Gets a bonus of 1/1 to Distance/Range");
        }

        if (_spellBonus)
        {
            CharacterDistance += _character.DistanceBonus;
            CharacterRange    += _character.RangeBonus;
            NoSimulationLog("Spell Bonus is Active. Character gets a bonus of {0} to Distance and {1} to Range", _character.DistanceBonus, _character.RangeBonus);
        }

        switch (_incident)
        {
        case Incidents.CosmicWeather:
            bossbonus = _season == CharacterSeasons.Summer;
            break;

        case Incidents.EndlessParty:
            boss1 = _edgeworkDefinedBoss;
            break;

        case Incidents.FairyWars:
            boss1     = _season == CharacterSeasons.Fall || _season == CharacterSeasons.Winter;
            bossbonus = _season == CharacterSeasons.Winter || _season == CharacterSeasons.Summer;
            break;

        case Incidents.LilyBlackandWhite:
            boss1     = _season == CharacterSeasons.Summer || _season == CharacterSeasons.Fall;
            bossbonus = _season == CharacterSeasons.Spring || _season == CharacterSeasons.Summer;
            break;

        case Incidents.LunarWar:
            boss1 = _edgeworkDefinedBoss;
            break;

        case Incidents.OccultInvasion:
            bossbonus = _season == CharacterSeasons.Spring || _season == CharacterSeasons.Summer;
            break;

        case Incidents.OverdrivenNight:
            boss1 = _season == CharacterSeasons.Fall || _season == CharacterSeasons.Winter;
            break;

        case Incidents.UndefinedFantasticObject:
            boss1 = _edgeworkDefinedBoss;
            break;

        case Incidents.ScarletMist:
            boss1 = _edgeworkDefinedBoss;
            break;

        case Incidents.WorldlyDesires:
            boss1 = Strikes;
            break;

        case Incidents.None:
            ForcePass("No idea why Incident.None was picked. That should not have happened.");
            return;

        default:
            ForcePass("Unknown Incident: {0}", _incident);
            return;
        }
        PrintIncident(incident, boss1, bossbonus, out BossDistance, out BossRange);

        foreach (Inventory item in _inventory.OrderBy(x => x.Item))
        {
            string footer = "";
            if (item == FindBestDistanceAdvantage)
            {
                int i = item.Distance;
                footer = " <--- Best Distance advantage";
                if (_inventory.Count(x => x.Distance == i) > 1)
                {
                    footer += " and worst Range disadvantage";
                }
            }
            else if (item == FindBestRangeAdvantage)
            {
                int i = item.Range;
                footer = " <--- Best Range advantage";
                if (_inventory.Count(x => x.Range == i) > 1)
                {
                    footer += " and worst Distance disadvantage";
                }
            }
            NoSimulationLog("Item: {0}, Distance: {1}, Range: {2}{3}", item.Item, item.Distance, item.Range, footer);
        }
        CharacterDistance += FindBestDistanceAdvantage.Distance;
        CharacterRange    += FindBestDistanceAdvantage.Range;

        CharacterDistance += FindBestRangeAdvantage.Distance;
        CharacterRange    += FindBestRangeAdvantage.Range;

        NoSimulationLog("Final character results - Distance = {0}, Range = {1}", CharacterDistance, CharacterRange);
        NoSimulationLog("Final Boss results - Distance = {0}, Range = {1}", BossDistance, BossRange);

        BossRange    += BossBuff;
        BossDistance += BossBuff;

        bool BossWins      = BossRange >= CharacterDistance;
        bool CharacterWins = CharacterRange >= BossDistance;

        if (CharacterWins)
        {
            NoSimulationLog(BossWins ? "Although the Boss was defeated, the character died in the process." : "The Boss was defeated and the character returned victorious");
        }
        else
        {
            NoSimulationLog(BossWins ? "The character was killed by the boss" : "The Battle ended in a stale-mate");
        }

        IncidentResult correctResult;

        if (CharacterWins && BossWins)
        {
            correctResult = _losses < 2 ? IncidentResult.Loss : IncidentResult.Win;
        }
        else
        {
            correctResult = CharacterWins ? IncidentResult.Win : IncidentResult.Loss;
        }
        NoSimulationLog("Expecting {0} to be pressed.", correctResult);

        if (!Strikes)
        {
            _correctIncidentResultEvenStrike = correctResult;
        }
        else
        {
            _correctIncidentResultOddStrike = correctResult;
        }

        if (boss1)
        {
            if (CharacterWins && BossWins)
            {
                _BOTHDEFEATEDLOSS = !_BOTHDEFEATEDLOSS;
                if (_BOTHDEFEATEDLOSS)
                {
                    _WINSBOSS1++;
                }
                else
                {
                    _LOSSESBOSS1++;
                }
            }
            else if (CharacterWins)
            {
                _WINSBOSS1++;
            }
            else
            {
                _LOSSESBOSS1++;
            }
        }
        else
        {
            if (CharacterWins && BossWins)
            {
                _BOTHDEFEATEDLOSS = !_BOTHDEFEATEDLOSS;
                if (_BOTHDEFEATEDLOSS)
                {
                    _WINSBOSS2++;
                }
                else
                {
                    _LOSSESBOSS2++;
                }
            }
            else if (CharacterWins)
            {
                _WINSBOSS2++;
            }
            else
            {
                _LOSSESBOSS2++;
            }
        }


        if (_incident == Incidents.WorldlyDesires)
        {
            NoSimulationLog(!Strikes ? "Done calculating for Even strikes" : "Done calculating for Odd strikes");
            if (!Strikes)
            {
                Strikes = true;
                goto OddStrikes;
            }
        }
        else
        {
            _correctIncidentResultOddStrike = _correctIncidentResultEvenStrike;
        }
    }
    private void SetEdgeworkBonus()
    {
        _characterBaseDistance = BombInfo.GetBatteryCount() == 0 ? 3 : BombInfo.GetBatteryCount();
        _characterBaseRange    = BombInfo.GetBatteryHolderCount() == 0 ? 3 : BombInfo.GetBatteryHolderCount();

        if (!_widgetbonus)
        {
            while (_characterBaseDistance > 5)
            {
                _characterBaseDistance -= 5;
            }
            while (_characterBaseRange > 5)
            {
                _characterBaseRange -= 5;
            }
        }
        else
        {
            while (_characterBaseDistance < 5)
            {
                _characterBaseDistance += 5;
            }
            while (_characterBaseRange < 5)
            {
                _characterBaseRange += 5;
            }
            while (_characterBaseDistance > 10)
            {
                _characterBaseDistance -= 5;
            }
            while (_characterBaseRange > 10)
            {
                _characterBaseRange -= 5;
            }
        }

        IncidentSet incident = new IncidentSet {
            Name = "Error"
        };

        if ((int)_incident < _incidedentSets.Count && (int)_incident >= 0)
        {
            incident = _incidedentSets[(int)_incident];
        }
        switch (_incident)
        {
        case Incidents.CosmicWeather:
            bool heavenlyNoEmptyPlatesBonus = BombInfo.GetPortPlates().All(x => x.Length != 0) && (BombInfo.GetPortCount() % 2) == 1;
            int  heavenlyBonus = (BombInfo.GetPortCount() / 2);
            if (heavenlyNoEmptyPlatesBonus)
            {
                heavenlyBonus++;
            }
            incident.Boss1.EdgeworkBonusDistance = heavenlyBonus;
            incident.EdgeworkBonusReason         = string.Format("port counts divided by two{0}", heavenlyNoEmptyPlatesBonus ? " rounded up" : " rounded down");
            break;

        case Incidents.EndlessParty:
            _edgeworkDefinedBoss = BombInfo.CountUniquePorts() < 3;
            int shamanBonus = BombInfo.GetSerialNumberNumbers().Min();
            if (shamanBonus == 0)
            {
                shamanBonus = 10;
            }
            incident.EdgeworkBonusReason         = "the last serial number digit";
            incident.Boss1.EdgeworkBonusDistance = shamanBonus;
            incident.Boss2.EdgeworkBonusRange    = shamanBonus;
            break;

        case Incidents.FairyWars:
            int FairyBonus = BombInfo.CountUniquePorts();
            incident.Boss1.EdgeworkBonusDistance = FairyBonus;
            incident.Boss1.EdgeworkBonusRange    = FairyBonus;
            incident.Boss2.EdgeworkBonusDistance = FairyBonus;
            incident.Boss2.EdgeworkBonusRange    = FairyBonus;
            incident.EdgeworkBonusReason         = "unique ports divided by two";
            break;

        case Incidents.LilyBlackandWhite:
            break;

        case Incidents.LunarWar:
            _edgeworkDefinedBoss = BombInfo.CountDuplicatePorts() != 1;
            if (BombInfo.GetSerialNumberNumbers().Sum() <= 11)
            {
                incident.Boss1.EdgeworkBonusDistance = incident.Boss1.BonusDistance;
                incident.Boss1.EdgeworkBonusRange    = incident.Boss1.BonusRange;
                incident.Boss2.EdgeworkBonusDistance = incident.Boss2.BonusDistance;
                incident.Boss2.EdgeworkBonusRange    = incident.Boss2.BonusRange;
                incident.EdgeworkBonusReason         = incident.BonusReason;
            }
            break;

        case Incidents.OccultInvasion:
            int  LegendaryBonus     = BombInfo.GetModuleNames().Count % 5;
            bool LegendaryIndicator = BombInfo.GetOnIndicators().Count(x => "LEGEND".Contains(x.ToUpperInvariant().ToCharArray().Last())) == 2;
            if (LegendaryBonus == 0 && LegendaryIndicator)
            {
                LegendaryBonus = 5;
            }
            incident.Boss1.EdgeworkBonusDistance = LegendaryBonus;
            incident.EdgeworkBonusReason         = LegendaryBonus == 5 ? "Two indicators ending in a letter contained in \"LEGEND\"" : "Module count modulo 5";
            break;

        case Incidents.OverdrivenNight:
            incident.Boss1.EdgeworkBonusRange = BombInfo.GetOffIndicators().Count();
            incident.Boss2.EdgeworkBonusRange = BombInfo.GetOffIndicators().Count();
            incident.EdgeworkBonusReason      = "the number of unlit Indicators";
            break;

        case Incidents.UndefinedFantasticObject:
            _edgeworkDefinedBoss = BombInfo.GetOffIndicators().Count() > BombInfo.GetOnIndicators().Count();
            int undefineduniqueports = BombInfo.CountUniquePorts();
            incident.Boss1.EdgeworkBonusDistance = undefineduniqueports;
            incident.Boss1.EdgeworkBonusRange    = undefineduniqueports;
            incident.Boss2.EdgeworkBonusRange    = undefineduniqueports;
            incident.EdgeworkBonusReason         = "the number of unique port types";
            break;

        case Incidents.ScarletMist:
            _edgeworkDefinedBoss = BombInfo.GetSerialNumberLetters().Count() > BombInfo.GetSerialNumberNumbers().Count();
            int scarletdisadvantage = BombInfo.GetOnIndicators().Count();
            if (_NO_SIMULATION_RUNNING)
            {
                _twofactorsum = BombInfo.IsTwoFactorPresent()
                        ? BombInfo.GetTwoFactorCodes().Sum(twofactor => twofactor % 10)
                        : BombInfo.GetSerialNumberNumbers().Last();
                foreach (int twofactor in BombInfo.GetTwoFactorCodes())
                {
                    BombModule.LogFormat("Two Factor code changed: {0}", twofactor);
                }
            }
            else
            {
                _twofactorsum = BombInfo.IsTwoFactorPresent()
                        ? 0
                        : BombInfo.GetSerialNumberNumbers().Last();
            }
            scarletdisadvantage += _twofactorsum;
            incident.Boss1.EdgeworkBonusDistance = -scarletdisadvantage;
            incident.Boss1.EdgeworkBonusRange    = -scarletdisadvantage;
            incident.Boss2.EdgeworkBonusDistance = -scarletdisadvantage;
            incident.Boss2.EdgeworkBonusRange    = -scarletdisadvantage;
            incident.EdgeworkBonusReason         = string.Format("based on the number of lit indicators and {0}", BombInfo.IsTwoFactorPresent() ? "two factor least significant digit sum" : "last serial number digit");
            break;

        case Incidents.WorldlyDesires:
            int hermitpenalty = -BombInfo.GetPortCount();
            incident.Boss1.EdgeworkBonusRange = hermitpenalty;
            incident.Boss2.EdgeworkBonusRange = hermitpenalty;
            incident.EdgeworkBonusReason      = "the number of ports";
            break;

        case Incidents.None:
            ForcePass("No idea why Incident.None was picked. That should not have happened.");
            return;

        default:
            ForcePass("Unknown Incident: {0}", _incident);
            return;
        }
    }
    IEnumerator SimulatateBattles(int debuff, int buff)
    {
        if (IsSimulationRunning)
        {
            IsItMyTurnYet       = BombModule.GetIDNumber();
            IsSimulationRunning = false;
        }
        yield return(null);

        yield return(null);

        _NO_SIMULATION_RUNNING = false;
        BombModule.LogFormat("DEBUGGING MODE ENABLED");
        while (IsItMyTurnYet < BombModule.GetIDNumber())
        {
            yield return(null);
        }
        IsSimulationRunning = true;

        if (_sets == 0)
        {
            InitializeItemSets();
        }

        if (!BombSerialNumber.Equals(BombInfo.GetSerialNumber()))
        {
            BombSerialNumber = BombInfo.GetSerialNumber();
            BombModule.LogFormat("------------------");
            BombModule.LogFormat("Simulation Results");
            BombModule.LogFormat("------------------");
            BombModule.LogFormat("");
            foreach (Incidents incident in _incidents.Skip(1))
            {
                _incident = incident;
                int battles = _sets * 4 * 2 * _characters.Count(x => x.ForbiddenIncident != _incident);
                SetEdgeworkBonus();

                IncidentSet incidentSet = _incidedentSets[(int)_incident];
                BombModule.LogFormat("Simulating Incident: {0}", incidentSet.Name);
                IncidentText.text           = _incident.ToString();
                InventoryText.characterSize = 0.7f;
                for (int j = debuff; j <= buff; j++)
                {
                    int i = 0;
                    foreach (Character c in _characters.Where(x => x.ForbiddenIncident != incident))
                    {
                        _character = c;
                        foreach (CharacterSeasons s in _seasons)
                        {
                            _season = s;
                            foreach (Inventory[] items in _itemSets.Values)
                            {
                                _inventory  = items.ToList();
                                _spellBonus = false;
                                Initialize(j, true);
                                _spellBonus = true;
                                Initialize(j, true);
                                i += 2;
                                if ((i % 50) == 0)
                                {
                                    UpdateDisplay(true, true, false, true);
                                    InventoryText.text = string.Format("{0}/{1}\n{2}: {3}/{4}", i + 1, battles, j < 0 ? "penalty" : "bonus", j, buff);
                                    yield return(null);
                                }
                            }
                        }
                    }
                    ReportWinResults(j, debuff != buff);
                }
            }
            BombModule.LogFormat("");
            BombModule.LogFormat("---------------");
            BombModule.LogFormat("Average Results");
            BombModule.LogFormat("---------------");
            BombModule.LogFormat("");
            foreach (Incidents incident in _incidents.Skip(1))
            {
                IncidentSet incidentSet = _incidedentSets[(int)incident];
                BombModule.LogFormat("Incident {0}:", incidentSet.Name);
                if (IncidentResults[incident][0] > 0)
                {
                    BombModule.LogFormat("Boss #1 ({0}): W/L: {1:0.##}/{2:0.##} ({3} Bombs)", incidentSet.Boss1.Name, (float)IncidentResults[incident][1] / IncidentResults[incident][0], (float)IncidentResults[incident][2] / IncidentResults[incident][0], IncidentResults[incident][0]);
                }

                if (IncidentResults[incident][3] > 0)
                {
                    BombModule.LogFormat("Boss #2 ({0}): W/L: {1:0.##}/{2:0.##} ({3} Bombs)", incidentSet.Boss2.Name, (float)IncidentResults[incident][4] / IncidentResults[incident][3], (float)IncidentResults[incident][5] / IncidentResults[incident][3], IncidentResults[incident][3]);
                }
            }
            BombModule.LogFormat("");
        }
        BombModule.LogFormat("--------------");
        BombModule.LogFormat("Battle Results");
        BombModule.LogFormat("--------------");
        BombModule.LogFormat("");
        _NO_SIMULATION_RUNNING = true;
        foreach (Incidents incident in _incidents.Skip(1))
        {
            BombModule.LogFormat("--------------");
            _incident = incident;
            Initialize();
            BombModule.LogFormat("--------------");
        }

        IsItMyTurnYet++;
        IsSimulationRunning = false;
        BombModule.HandlePass();
        if (IsItMyTurnYet <= KMBombModuleExtensions.HighestConsecutiveID)
        {
            yield break;
        }
        yield return(new WaitForSeconds(1));

        BombModule.HandleStrike();
    }