Beispiel #1
0
 private void UpdateOpponentsNumber()
 {
     if (!Mode.CandidatesMode)
     {
         SetOpponentsNumberInternal(NonfilteredList.ApartFrom(_playerEntry).Count());
     }
 }
Beispiel #2
0
        private void UpdatePlayerEntry()
        {
            if (_playerCar != _playerEntry?.Car)
            {
                if (_playerEntry != null)
                {
                    NonfilteredList.Remove(_playerEntry);
                    _playerEntry = null;
                }

                if (Mode != BuiltInGridMode.Custom || IgnoreStartingPosition)
                {
                    return;
                }
                _playerEntry = _playerCar == null ? null : new RaceGridPlayerEntry(_playerCar);
            }

            if (_playerEntry == null)
            {
                return;
            }
            if (Mode == BuiltInGridMode.Custom)
            {
                var index = NonfilteredList.IndexOf(_playerEntry);
                var pos   = StartingPosition - 1;

                if (index == -1)
                {
                    if (pos > NonfilteredList.Count)
                    {
                        NonfilteredList.Add(_playerEntry);
                    }
                    else if (pos >= 0)
                    {
                        NonfilteredList.Insert(pos, _playerEntry);
                    }
                }
                else
                {
                    if (pos < 0)
                    {
                        NonfilteredList.RemoveAt(index);
                    }
                    else if (pos != index)
                    {
                        NonfilteredList.Move(index, pos);
                    }
                }
            }
            else if (NonfilteredList.Contains(_playerEntry))
            {
                NonfilteredList.Remove(_playerEntry);
                _playerEntry = null;
            }
        }
Beispiel #3
0
 private void UpdateExceeded()
 {
     if (Mode.CandidatesMode)
     {
         foreach (var entry in NonfilteredList.Where(x => x.ExceedsLimit))
         {
             entry.ExceedsLimit = false;
         }
     }
     else
     {
         var left = OpponentsNumberLimit;
         foreach (var entry in NonfilteredList.ApartFrom(_playerEntry))
         {
             entry.ExceedsLimit = --left < 0;
         }
     }
 }
Beispiel #4
0
        public void DeleteEntry(RaceGridEntry entry)
        {
            if (entry is RaceGridPlayerEntry)
            {
                StartingPosition = 0;
                return;
            }

            NonfilteredList.Remove(entry);
            if (Mode == BuiltInGridMode.Custom)
            {
                UpdateOpponentsNumber();
            }
            else
            {
                Mode = BuiltInGridMode.CandidatesManual;
            }

            UpdateExceeded();
        }
Beispiel #5
0
        private async Task RebuildGridAsyncInner()
        {
            try {
                await Task.Delay(50);

                OnPropertyChanged(nameof(IsBusy));
                ErrorMessage = null;

again:
                var mode = Mode;
                var candidates = await FindCandidates();

                if (mode != Mode)
                {
                    goto again;
                }

                // I’ve seen that XKCD comic, but I still think goto is more
                // suitable than a loop here

                if (candidates == null)
                {
                    return;
                }
                NonfilteredList.ReplaceEverythingBy(candidates);
            } catch (SyntaxErrorException e) {
                ErrorMessage = string.Format(ToolsStrings.Common_SyntaxErrorFormat, e.Message);
                NonfatalError.Notify(ToolsStrings.RaceGrid_CannotUpdate, e);
            } catch (ScriptRuntimeException e) {
                ErrorMessage = e.Message;
            } catch (InformativeException e) when(e.SolutionCommentary == null)
            {
                ErrorMessage = e.Message;
            } catch (Exception e) {
                ErrorMessage = e.Message;
                NonfatalError.Notify(ToolsStrings.RaceGrid_CannotUpdate, e);
            } finally {
                _rebuildingTask = null;
                OnPropertyChanged(nameof(IsBusy));
            }
        }
Beispiel #6
0
        public RaceGridViewModel(bool ignoreStartingPosition = false, [CanBeNull] string keySaveable = KeySaveable)
        {
            IgnoreStartingPosition = ignoreStartingPosition;

            _saveable = new SaveHelper <SaveableData>(keySaveable, () => {
                var data = new SaveableData {
                    ModeId                = Mode.Id,
                    FilterValue           = FilterValue,
                    ShuffleCandidates     = ShuffleCandidates,
                    AiLevelFixed          = AiLevelFixed,
                    AiLevelArrangeRandom  = AiLevelArrangeRandom,
                    AiLevelArrangeReverse = AiLevelArrangeReverse,
                    AiLevel               = AiLevel,
                    AiLevelMin            = AiLevelMin,
                    OpponentsNumber       = OpponentsNumber,
                    StartingPosition      = StartingPosition,
                };

                if (Mode == BuiltInGridMode.CandidatesManual)
                {
                    var priority = false;
                    data.CarIds  = NonfilteredList.Select(x => {
                        if (x.CandidatePriority != 1)
                        {
                            priority = true;
                        }
                        return(x.Car.Id);
                    }).ToArray();

                    if (priority)
                    {
                        data.CandidatePriorities = NonfilteredList.Select(x => x.CandidatePriority).ToArray();
                    }
                }
                else if (Mode == BuiltInGridMode.Custom)
                {
                    data.CarIds = NonfilteredList.Where(x => !x.SpecialEntry).Select(x => x.Car.Id).ToArray();
                }

                if (data.CarIds != null)
                {
                    var filtered = NonfilteredList.Where(x => !x.SpecialEntry).ToList();

                    if (filtered.Any(x => x.AiLevel.HasValue))
                    {
                        data.AiLevels = filtered.Select(x => x.AiLevel ?? -1).ToArray();
                    }

                    if (filtered.Any(x => x.Name != null))
                    {
                        data.Names = filtered.Select(x => x.Name).ToArray();
                    }

                    if (filtered.Any(x => x.Nationality != null))
                    {
                        data.Nationalities = filtered.Select(x => x.Nationality).ToArray();
                    }

                    if (filtered.Any(x => x.CarSkin != null))
                    {
                        data.SkinIds = filtered.Select(x => x.CarSkin?.Id).ToArray();
                    }
                }

                return(data);
            }, data => {
                ShuffleCandidates    = data.ShuffleCandidates ?? true;
                AiLevelFixed         = data.AiLevelFixed ?? false;
                AiLevelArrangeRandom = data.AiLevelArrangeRandomly.HasValue ? (data.AiLevelArrangeRandomly.Value ? 1d : 0d) :
                                       data.AiLevelArrangeRandom ?? 0.1d;
                AiLevelArrangeReverse = data.AiLevelArrangeReverse ?? false;
                AiLevel    = data.AiLevel ?? 95;
                AiLevelMin = data.AiLevelMin ?? 85;

                FilterValue  = data.FilterValue;
                ErrorMessage = null;

                var mode = Modes.GetByIdOrDefault <IRaceGridMode>(data.ModeId);
                if (mode == null)
                {
                    NonfatalError.NotifyBackground(ToolsStrings.RaceGrid_GridModeIsMissing,
                                                   string.Format(ToolsStrings.RaceGrid_GridModeIsMissing_Commentary, data.ModeId));
                    Mode = BuiltInGridMode.SameCar;
                }
                else
                {
                    Mode = mode;
                }

                if (Mode.CandidatesMode)
                {
                    if (Mode == BuiltInGridMode.CandidatesManual && data.CarIds != null)
                    {
                        // TODO: Async?
                        NonfilteredList.ReplaceEverythingBy(data.CarIds.Select(x => CarsManager.Instance.GetById(x)).Select((x, i) => {
                            if (x == null)
                            {
                                return(null);
                            }

                            var aiLevel   = data.AiLevels?.ElementAtOrDefault(i);
                            var carSkinId = data.SkinIds?.ElementAtOrDefault(i);
                            return(new RaceGridEntry(x)
                            {
                                CandidatePriority = data.CandidatePriorities?.ElementAtOr(i, 1) ?? 1,
                                AiLevel = aiLevel >= 0 ? aiLevel : (int?)null,
                                Name = data.Names?.ElementAtOrDefault(i),
                                Nationality = data.Nationalities?.ElementAtOrDefault(i),
                                CarSkin = carSkinId != null ? x.GetSkinById(carSkinId) : null,
                            });
                        }).NonNull());
                    }
                    else
                    {
                        NonfilteredList.Clear();
                    }

                    SetOpponentsNumberInternal(data.OpponentsNumber ?? 7);
                }
                else
                {
                    NonfilteredList.ReplaceEverythingBy(data.CarIds?.Select(x => CarsManager.Instance.GetById(x)).Select((x, i) => {
                        if (x == null)
                        {
                            return(null);
                        }

                        var aiLevel   = data.AiLevels?.ElementAtOrDefault(i);
                        var carSkinId = data.SkinIds?.ElementAtOrDefault(i);

                        return(new RaceGridEntry(x)
                        {
                            AiLevel = aiLevel >= 0 ? aiLevel : null,
                            Name = data.Names?.ElementAtOrDefault(i),
                            Nationality = data.Nationalities?.ElementAtOrDefault(i),
                            CarSkin = carSkinId != null ? x.GetSkinById(carSkinId) : null,
                        });
                    }).NonNull() ?? new RaceGridEntry[0]);
                }

                StartingPosition = data.StartingPosition ?? 7;
                FinishLoading();
            }, Reset);

            _presetsHelper = new PresetsMenuHelper();

            _randomGroup = new HierarchicalGroup(ToolsStrings.RaceGrid_Random);
            UpdateRandomModes();

            Modes = new HierarchicalGroup {
                BuiltInGridMode.SameCar,
                _randomGroup,
                BuiltInGridMode.Custom,
                _presetsHelper.Create(PresetableKeyValue, p => {
                    ImportFromPresetData(p.ReadData());
                }, ControlsStrings.Common_Presets)
            };

            NonfilteredList.CollectionChanged   += OnCollectionChanged;
            NonfilteredList.ItemPropertyChanged += OnItemPropertyChanged;
            FilteredView = new BetterListCollectionView(NonfilteredList)
            {
                CustomSort = this
            };

            // _saveable.Initialize();
            FilesStorage.Instance.Watcher(ContentCategory.GridTypes).Update += OnGridTypesUpdate;
        }
Beispiel #7
0
        public async Task <IList <Game.AiCar> > GenerateGameEntries(CancellationToken cancellation = default(CancellationToken))
        {
            if (IsBusy)
            {
                await RebuildGridAsync();

                if (cancellation.IsCancellationRequested)
                {
                    return(null);
                }
            }

            var opponentsNumber = OpponentsNumberLimited;

            if (FilteredView.Count == 0 || opponentsNumber == 0)
            {
                return(new Game.AiCar[0]);
            }

            var skins = new Dictionary <string, GoodShuffle <CarSkinObject> >();

            foreach (var car in FilteredView.OfType <RaceGridEntry>().Where(x => x.CarSkin == null).Select(x => x.Car).Distinct())
            {
                await car.SkinsManager.EnsureLoadedAsync();

                if (cancellation.IsCancellationRequested)
                {
                    return(null);
                }

                skins[car.Id] = GoodShuffle.Get(car.EnabledOnlySkins);
            }

            NameNationality[] nameNationalities;
            if (opponentsNumber == 7 && OptionNfsPorscheNames)
            {
                nameNationalities = new[] {
                    new NameNationality {
                        Name = "Dylan", Nationality = "Wales"
                    },
                    new NameNationality {
                        Name = "Parise", Nationality = "Italy"
                    },
                    new NameNationality {
                        Name = "Steele", Nationality = "United States"
                    },
                    new NameNationality {
                        Name = "Wingnut", Nationality = "England"
                    },
                    new NameNationality {
                        Name = "Leadfoot", Nationality = "Australia"
                    },
                    new NameNationality {
                        Name = "Amazon", Nationality = "United States"
                    },
                    new NameNationality {
                        Name = "Backlash", Nationality = "United States"
                    }
                };
            }
            else if (DataProvider.Instance.NationalitiesAndNames.Any())
            {
                nameNationalities = GoodShuffle.Get(DataProvider.Instance.NationalitiesAndNamesList).Take(opponentsNumber).ToArray();
            }
            else
            {
                nameNationalities = null;
            }

            List <int> aiLevels;

            if (AiLevelFixed)
            {
                aiLevels = null;
            }
            else
            {
                var aiLevelsInner = from i in Enumerable.Range(0, opponentsNumber)
                                    select AiLevelMin + ((opponentsNumber < 2 ? 1d : 1d - i / (opponentsNumber - 1d)) * (AiLevel - AiLevelMin)).RoundToInt();
                if (AiLevelArrangeReverse)
                {
                    aiLevelsInner = aiLevelsInner.Reverse();
                }

                if (Equals(AiLevelArrangeRandom, 1d))
                {
                    aiLevelsInner = GoodShuffle.Get(aiLevelsInner);
                }
                else if (AiLevelArrangeRandom > 0d)
                {
                    aiLevelsInner = LimitedShuffle.Get(aiLevelsInner, AiLevelArrangeRandom);
                }

                aiLevels = aiLevelsInner.Take(opponentsNumber).ToList();
                Logging.Debug("AI levels: " + aiLevels.Select(x => $@"{x}%").JoinToString(@", "));
            }

            IEnumerable <RaceGridEntry> final;

            if (Mode.CandidatesMode)
            {
                var list = FilteredView.OfType <RaceGridEntry>().SelectMany(x => new[] { x }.Repeat(x.CandidatePriority)).ToList();

                if (ShuffleCandidates)
                {
                    var shuffled = GoodShuffle.Get(list);

                    if (_playerCar != null)
                    {
                        var same = list.FirstOrDefault(x => x.Car == _playerCar);
                        if (same != null)
                        {
                            shuffled.IgnoreOnce(same);
                        }
                    }

                    final = shuffled.Take(opponentsNumber);
                }
                else
                {
                    var skip = _playerCar;
                    final = LinqExtension.RangeFrom().Select(x => list.RandomElement()).Where(x => {
                        if (x.Car == skip)
                        {
                            skip = null;
                            return(false);
                        }

                        return(true);
                    }).Take(opponentsNumber);
                }
            }
            else
            {
                final = NonfilteredList.Where(x => !x.SpecialEntry);
            }

            if (_playerCar != null)
            {
                skins.GetValueOrDefault(_playerCar.Id)?.IgnoreOnce(_playerCar.SelectedSkin);
            }

            var takenNames = new List <string>(opponentsNumber);

            return(final.Take(opponentsNumber).Select((entry, i) => {
                var level = entry.AiLevel ?? aiLevels?[i] ?? 100;

                var skin = entry.CarSkin;
                if (skin == null)
                {
                    skin = skins.GetValueOrDefault(entry.Car.Id)?.Next;
                }

                var name = entry.Name;
                if (string.IsNullOrWhiteSpace(name) && SettingsHolder.Drive.QuickDriveUseSkinNames)
                {
                    var skinDriverNames = skin?.DriverName?.Split(',').Select(x => x.Trim()).Where(x => x.Length > 0).ToList();
                    if (skinDriverNames?.Count > 0)
                    {
                        name = GoodShuffle.Get(skinDriverNames).Take(skinDriverNames.Count).FirstOrDefault(x => !takenNames.Contains(x)) ?? name;
                        takenNames.Add(name);
                    }
                }

                if (string.IsNullOrWhiteSpace(name))
                {
                    name = nameNationalities?[i].Name ?? @"AI #" + i;
                    takenNames.Add(name);
                }

                var nationality = entry.Nationality ?? nameNationalities?[i].Nationality ?? @"Italy";
                var skinId = skin?.Id;

                return new Game.AiCar {
                    AiLevel = level,
                    CarId = entry.Car.Id,
                    DriverName = AiLevelInDriverName ? $@"{name} ({level}%)" : name,
                    Nationality = nationality,
                    Setup = "",
                    SkinId = skinId
                };
            }).ToList());
        }
Beispiel #8
0
        public void InsertEntry(int index, [NotNull] RaceGridEntry entry)
        {
            var oldIndex = NonfilteredList.IndexOf(entry);

            var count = NonfilteredList.Count;
            var isNew = oldIndex == -1;
            var limit = isNew ? count : count - 1;

            if (index < 0 || index > limit)
            {
                index = limit;
            }

            if (oldIndex == index)
            {
                return;
            }
            if (Mode.CandidatesMode)
            {
                if (isNew)
                {
                    Mode = BuiltInGridMode.CandidatesManual;

                    var existed = NonfilteredList.FirstOrDefault(x => x.Same(entry));
                    if (existed != null)
                    {
                        existed.CandidatePriority++;
                    }
                    else
                    {
                        NonfilteredList.Add(entry);
                    }

                    return;
                }

                NonfilteredList.ReplaceEverythingBy(NonfilteredList.Sort(Compare));
                NonfilteredList.Move(oldIndex, index);

                try {
                    _modeKeepOrder = true;
                    Mode           = BuiltInGridMode.Custom;
                } finally {
                    _modeKeepOrder = false;
                }
            }
            else if (isNew)
            {
                if (index == count)
                {
                    NonfilteredList.Add(entry);
                }
                else
                {
                    NonfilteredList.Insert(index, entry);
                }

                UpdateOpponentsNumber();
            }
            else if (index != oldIndex)
            {
                NonfilteredList.Move(oldIndex, index);
            }

            if (StartingPosition != 0)
            {
                StartingPositionLimited = NonfilteredList.IndexOf(_playerEntry) + 1;
            }

            UpdateExceeded();
        }