public GameDialog(Game.Result readyResult) { _resultsViewMode = true; DataContext = new ViewModel(); InitializeComponent(); OnResult(readyResult, null); }
public string AttackFaceUpOpponent(MonsterCard attackingCard, MonsterCard defendingCard) { Game.Result r = myCurrentGame.RequestAttack(id, attackingCard, defendingCard); if (r.Equals(Game.Result.Success)) { return(""); } else { return(r.ToString()); } }
public string AttackLifePoints(MonsterCard attackingCard) { Game.Result r = myCurrentGame.RequestAttackLifePoints(id, attackingCard); if (r.Equals(Game.Result.Success)) { return(""); } else { return(r.ToString()); } }
/// <summary> /// Asks the game to change the mode of the card (to attack mode or defense mode). /// </summary> /// <param name="toChangeModeOf">to change to attack mode or defense mode</param> /// <returns>"" if successful. Error message if Error</returns> public string ChangeModeOfCard(MonsterCard toChangeModeOf) { Game.Result r = myCurrentGame.RequestChangeModeOfCard(id, toChangeModeOf); if (r.Equals(Game.Result.Success)) { return(""); } else { return(r.ToString()); } }
public string TryEquip(Object EquipableCard, string nameOfCardToEquipTo) { bool found = false; if (hand.Contains(EquipableCard)) { for (int i = 0; i < faceDownCardsInMonsterZone.Count && !found; i++) { if (faceDownCardsInMonsterZone[i].getName().Equals(nameOfCardToEquipTo)) { MonsterCard equippingTo = faceDownCardsInMonsterZone[i]; found = true; Game.Result r = myCurrentGame.RequestEquip(id, EquipableCard, ref equippingTo); if (r == Game.Result.Success) { faceDownCardsInMonsterZone[i] = equippingTo; SendToGraveYard(EquipableCard, Zone.Hand); return(""); } else { return(r.ToString()); } } } IList <MonsterCard> faceUpMonsters = m_meReadOnly.getFaceUpMonstersInMonsterZone(); for (int i = 0; i < faceUpMonsters.Count && !found; i++) { if (faceUpMonsters[i].getName().Equals(nameOfCardToEquipTo)) { found = true; MonsterCard equippingTo = faceUpMonsters[i]; Game.Result r = myCurrentGame.RequestEquip(id, EquipableCard, ref equippingTo); if (r == Game.Result.Success) { faceUpMonsters[i] = equippingTo; m_meReadOnly.setFaceUpMonstersInMonsterZone(faceUpMonsters); SendToGraveYard(EquipableCard, Zone.Hand); return(""); } else { return(r.ToString()); } } } return("Failed to find card"); } else { return("Equipable Card not in hand anymore."); } }
/// <summary> /// Tell the game and opponent you are done for this turn. Should be called after you attack, summon, etc. /// </summary> /// <returns>"" if successfully ended turn. Error string if failed.</returns> public string EndTurn() { Game.Result r = myCurrentGame.RequestEndTurn(id); if (r == Game.Result.Success) { return(""); } else { return(r.ToString()); } }
internal ReplayHelper(Game.StartProperties startProperties, Game.Result result) { OriginalFilename = Path.Combine(FileUtils.GetReplaysDirectory(), ReplayObject.PreviousReplayName); RenamedFilename = FileUtils.EnsureUnique(OriginalFilename); Name = GetReplayName(startProperties, result); IsAvailable = File.Exists(OriginalFilename); if (IsAvailable && SettingsHolder.Drive.AutoSaveReplays) { IsRenamed = true; } }
public string Sacrifice(MonsterCard toSacrifice) { Game.Result r = myCurrentGame.RequestSacrifice(id, toSacrifice); if (r.Equals(Game.Result.Success)) { return(""); } else { return(r.ToString()); } }
public string AttackFaceDownOpponent(MonsterCard attackingCard, Mode faceDownCardsMode) { Game.Result r = myCurrentGame.RequestAttackOnFaceDownCard(id, attackingCard, faceDownCardsMode); if (r.Equals(Game.Result.Success)) { return(""); } else { return(r.ToString()); } }
public void AddNewResult([NotNull] Game.StartProperties startProperties, [NotNull] Game.Result result) { var directory = SessionsDirectory; FileUtils.EnsureDirectoryExists(directory); var fileName = DateTime.Now.ToString("yyMMdd-HHmmss") + ".json"; var raceOut = AcPaths.GetResultJsonFilename(); JObject data = null; if (File.Exists(raceOut)) { try { // Let’s try to save original data instead in case we missed something during parsing. // But let’s remove formatting just in case. data = JObject.Parse(File.ReadAllText(raceOut)); } catch (Exception e) { Logging.Warning(e); } } if (data == null) { data = JObject.FromObject(result); } // Trying to keep race params as well… // TODO: Do it the other way around, from start params? var raceIni = AcPaths.GetRaceIniFilename(); if (File.Exists(raceIni)) { data[KeyRaceIni] = File.ReadAllText(raceIni); } var quickDrive = startProperties.GetAdditional <QuickDrivePresetProperty>(); if (quickDrive?.SerializedData != null) { data[KeyQuickDrive] = quickDrive.SerializedData; } File.WriteAllText(FileUtils.EnsureUnique(Path.Combine(directory, fileName)), data.ToString(Formatting.None)); }
public int GetTakenPlace(Game.Result result) { if (result == null) { return(UnremarkablePlace); } var drift = result.GetExtraByType <Game.ResultExtraDrift>(); if (drift != null && Type == PlaceConditionsType.Points) { return(GetTakenPlace(drift.Points)); } var timeAttack = result.GetExtraByType <Game.ResultExtraTimeAttack>(); if (timeAttack != null && Type == PlaceConditionsType.Points) { return(GetTakenPlace(timeAttack.Points)); } var drag = result.GetExtraByType <Game.ResultExtraDrag>(); if (drag != null && Type == PlaceConditionsType.Wins) { return(GetTakenPlace(drag.Wins)); } switch (Type) { case PlaceConditionsType.Points: case PlaceConditionsType.Wins: return(UnremarkablePlace); case PlaceConditionsType.Position: var place = result.Sessions?.LastOrDefault(x => x.BestLaps?.Any() == true)?.CarPerTakenPlace?.IndexOf(0); return(place.HasValue ? GetTakenPlace(place.Value + 1) : UnremarkablePlace); case PlaceConditionsType.Time: var time = result.Sessions?.LastOrDefault(x => x.BestLaps?.Any() == true)?.BestLaps?.FirstOrDefault(x => x.CarNumber == 0)?.Time; return(time.HasValue ? GetTakenPlace((int)time.Value.TotalMilliseconds) : UnremarkablePlace); default: throw new ArgumentOutOfRangeException(); } }
/// <summary> /// A request to normal summon the monster is given to the game class. If allowable, it will be summoned. /// </summary> /// <param name="monsterToSummon">A MonsterCard to play.</param> /// <returns>"" if successful. Error string if failed.</returns> public string NormalSummon(Object monsterToSummon) { if (monsterToSummon is MonsterCard && hand.Contains(monsterToSummon)) { Game.Result amIAllowedToSummon = myCurrentGame.RequestNormalSummon(id, monsterToSummon, faceDownCardsInMonsterZone.Count + m_meReadOnly.getFaceUpMonstersInMonsterZone().Count); if (amIAllowedToSummon.ToString().Equals("Success")) { return(""); } else { return(amIAllowedToSummon.ToString()); } } else { return("Either Card is not a monster or the card is not in your hand!"); } }
public static string GetType(Game.StartProperties startProperties, [CanBeNull] Game.Result result) { // TODO: drag mode if (startProperties.ModeProperties is Game.DriftProperties) { return("Drift"); } if (startProperties.ModeProperties is Game.TimeAttackProperties) { return("Time Attack"); } if (startProperties.ModeProperties is Game.HotlapProperties) { return("Hotlap"); } if (startProperties.ModeProperties is Game.OnlineProperties) { return("Online"); } if (startProperties.ModeProperties is Game.PracticeProperties) { return("Practice"); } if (result?.Sessions?.Length == 1) { return("Race"); } if (result?.Sessions?.Length > 1) { return("Weekend"); } return(startProperties.ModeProperties is Game.RaceProperties ? "Race" : "Something Unspeakable"); }
private static string GetValue(Game.StartProperties startProperties, [CanBeNull] Game.Result result, string key) { if (startProperties.BasicProperties == null) { return(null); } switch (key) { case "type": return(GetType(startProperties, result)); case "car": return(CarsManager.Instance.GetById(startProperties.BasicProperties.CarId)?.DisplayName); case "car.id": return(startProperties.BasicProperties.CarId); case "track": var track = TracksManager.Instance.GetById(startProperties.BasicProperties.TrackId); var config = startProperties.BasicProperties.TrackConfigurationId != null ? track?.GetLayoutByLayoutId(startProperties.BasicProperties.TrackConfigurationId) : track; return(config?.Name); case "track.id": return(startProperties.BasicProperties.TrackId); case "date": return(startProperties.StartTime.ToString(CultureInfo.CurrentCulture)); case "date_ac": return(GetAcDate(startProperties.StartTime)); default: return(null); } }
void IGameUi.OnResult(Game.Result result, ReplayHelper replayHelper) { EnableRenderer(false); ProgressBar.Visibility = Visibility.Collapsed; var time = result?.GetExtraByType <Game.ResultExtraBestLap>()?.Time; if (!time.HasValue || time.Value == TimeSpan.Zero) { _bestLapTime = null; RevertUi(true); } else { _resultShown = true; _bestLapTime = time; LoadingText.Visibility = Visibility.Visible; LoadingText.FontSize = 20d; LoadingText.Text = "Best time: " + string.Format("{0:mm}:{0:ss}:{0:fff}", time.Value); GameResultOk.Visibility = Visibility.Visible; PlayerNamePanel.Visibility = Visibility.Visible; } }
public static string Process([NotNull] string str, [NotNull] Game.StartProperties startProperties, [CanBeNull] Game.Result result) { if (startProperties == null) { throw new ArgumentNullException(nameof(startProperties)); } if (str == null) { throw new ArgumentNullException(nameof(str)); } return(ReplayNameRegex.Replace(str, match => { var value = GetValue(startProperties, result, match.Groups[1].Value)?.Trim(); if (string.IsNullOrEmpty(value)) { return "-"; } foreach (var c in match.Groups[2].Success ? match.Groups[2].Value.ToLowerInvariant() : string.Empty) { switch (c) { case 'l': value = value.ToLowerInvariant(); break; case 'u': value = value.ToUpperInvariant(); break; case '0': value = value.Substring(0, 1); break; default: Logging.Warning("Unsupported modifier: " + c); break; } } return value; })); }
public GameFinishedArgs([NotNull] Game.StartProperties startProperties, Game.Result result) { StartProperties = startProperties; Result = result; }
void IGameUi.OnResult(Game.Result result, ReplayHelper replayHelper) { if (result != null && result.NumberOfSessions == 1 && result.Sessions.Length == 1 && result.Sessions[0].Type == Game.SessionType.Practice && SettingsHolder.Drive.SkipPracticeResults || _properties?.ReplayProperties != null || _properties?.BenchmarkProperties != null) { Close(); return; } /* save replay button * / * Func<string> buttonText = () => replayHelper?.IsReplayRenamed == true ? * AppStrings.RaceResult_UnsaveReplay : AppStrings.RaceResult_SaveReplay; * * var saveReplayButton = CreateExtraDialogButton(buttonText(), () => { * if (replayHelper == null) { * Logging.Warning("ReplayHelper=<NULL>"); * return; * } * * replayHelper.IsReplayRenamed = !replayHelper.IsReplayRenamed; * }); * * if (replayHelper == null) { * saveReplayButton.IsEnabled = false; * } else { * replayHelper.PropertyChanged += (sender, args) => { * if (args.PropertyName == nameof(ReplayHelper.IsReplayRenamed)) { * saveReplayButton.Content = buttonText(); * } * }; * } * * /* save replay alt button */ ButtonWithComboBox saveReplayButton; if (replayHelper != null) { Func <string> buttonText = () => replayHelper.IsRenamed ? AppStrings.RaceResult_UnsaveReplay : AppStrings.RaceResult_SaveReplay; Func <string> saveAsText = () => string.Format(replayHelper.IsRenamed ? "Saved as “{0}”" : "Save as “{0}”", replayHelper.Name); saveReplayButton = new ButtonWithComboBox { Margin = new Thickness(4, 0, 0, 0), MinHeight = 21, MinWidth = 65, Content = ToolsStrings.Shared_Replay, Command = new AsyncCommand(replayHelper.Play), MenuItems = { new MenuItem { Header = saveAsText(), Command = new DelegateCommand(() =>{ var newName = Prompt.Show("Save replay as:", "Replay Name", replayHelper.Name, "?", required: true); if (!string.IsNullOrWhiteSpace(newName)) { replayHelper.Name = newName; } replayHelper.IsRenamed = true; }) }, new MenuItem { Header = buttonText(), Command = new DelegateCommand(replayHelper.Rename) }, new Separator(), new MenuItem { Header = "Share Replay", Command = new AsyncCommand(() =>{ var car = _properties?.BasicProperties?.CarId == null ? null : CarsManager.Instance.GetById(_properties.BasicProperties.CarId); var track = _properties?.BasicProperties?.TrackId == null ? null : TracksManager.Instance.GetById(_properties.BasicProperties.TrackId); return(SelectedReplayPage.ShareReplay(replayHelper.Name, replayHelper.Filename, car, track)); }) }, } }; replayHelper.PropertyChanged += (sender, args) => { if (args.PropertyName == nameof(ReplayHelper.IsRenamed)) { ((MenuItem)saveReplayButton.MenuItems[0]).Header = saveAsText(); ((MenuItem)saveReplayButton.MenuItems[1]).Header = buttonText(); } }; } else { saveReplayButton = null; } var tryAgainButton = CreateExtraDialogButton(AppStrings.RaceResult_TryAgain, () => { CloseWithResult(MessageBoxResult.None); GameWrapper.StartAsync(_properties).Forget(); }); Button fixButton = null; if (result == null || !result.IsNotCancelled) { Model.CurrentState = ViewModel.State.Cancelled; var whatsGoingOn = _properties?.GetAdditional <WhatsGoingOn>(); fixButton = this.CreateFixItButton(whatsGoingOn?.Solution); Model.ErrorMessage = whatsGoingOn?.GetDescription(); } else { try { Model.CurrentState = ViewModel.State.Finished; Model.FinishedData = GetFinishedData(_properties, result); } catch (Exception e) { Logging.Warning(e); Model.CurrentState = ViewModel.State.Error; Model.ErrorMessage = AppStrings.RaceResult_ResultProcessingError; Buttons = new[] { CloseButton }; return; } } Buttons = new[] { fixButton, fixButton == null ? saveReplayButton : null, fixButton == null ? tryAgainButton : null, CloseButton }; }
public GameEndedArgs([NotNull] Game.StartProperties startProperties, [CanBeNull] Game.Result result) { StartProperties = startProperties; Result = result; }
private static string GetReplayName([CanBeNull] Game.StartProperties startProperties, [CanBeNull] Game.Result result) { if (startProperties == null) { return($"_autosave_{DateTime.Now.ToMillisecondsTimestamp()}.acreplay"); } var s = SettingsHolder.Drive.ReplaysNameFormat; if (string.IsNullOrEmpty(s)) { s = SettingsHolder.Drive.DefaultReplaysNameFormat; } return(FileUtils.EnsureFileNameIsValid(VariablesReplacement.Process(s, startProperties, result))); }
private static BaseFinishedData GetFinishedData(Game.StartProperties properties, Game.Result result) { var conditions = properties?.GetAdditional <PlaceConditions>(); var takenPlace = conditions?.GetTakenPlace(result) ?? PlaceConditions.UnremarkablePlace; Logging.Debug($"Place conditions: {conditions?.GetDescription()}, result: {result.GetDescription()}"); if (result.GetExtraByType <Game.ResultExtraDrift>(out var drift)) { return(new DriftFinishedData { Points = drift.Points, MaxCombo = drift.MaxCombo, MaxLevel = drift.MaxLevel, TakenPlace = takenPlace }); } if (result.GetExtraByType <Game.ResultExtraTimeAttack>(out var timeAttack)) { var bestLapTime = result.Sessions?.SelectMany(x => from lap in x.BestLaps where lap.CarNumber == 0 select lap.Time).MinOrDefault(); return(new TimeAttackFinishedData { Points = timeAttack.Points, Laps = result.Sessions?.Sum(x => x.LapsTotalPerCar?.FirstOrDefault() ?? 0) ?? 0, BestLapTime = bestLapTime == TimeSpan.Zero ? null : bestLapTime, TakenPlace = takenPlace }); } if (result.GetExtraByType <Game.ResultExtraBestLap>(out var bestLap) && bestLap.IsNotCancelled && result.Sessions?.Length == 1 && result.Players?.Length == 1) { var bestLapTime = result.Sessions.SelectMany(x => from lap in x.BestLaps where lap.CarNumber == 0 select lap.Time).MinOrDefault(); var sectorsPerSections = result.Sessions.SelectMany(x => from lap in x.Laps where lap.CarNumber == 0 select lap.SectorsTime).ToList(); var theoreticallLapTime = sectorsPerSections.FirstOrDefault()?.Select((x, i) => sectorsPerSections.Select(y => y[i]).Min()).Sum(); return(result.Sessions[0].Name == AppStrings.Rsr_SessionName ? new RsrFinishedData { Laps = result.Sessions.Sum(x => x.LapsTotalPerCar?.FirstOrDefault() ?? 0), BestLapTime = bestLapTime == TimeSpan.Zero ? (TimeSpan?)null : bestLapTime, TheoreticallLapTime = theoreticallLapTime, TakenPlace = takenPlace } : new HotlapFinishedData { Laps = result.Sessions.Sum(x => x.LapsTotalPerCar?.FirstOrDefault() ?? 0), BestLapTime = bestLapTime == TimeSpan.Zero ? (TimeSpan?)null : bestLapTime, TheoreticallLapTime = theoreticallLapTime, TakenPlace = takenPlace }); } var isOnline = properties?.ModeProperties is Game.OnlineProperties; var playerName = isOnline && SettingsHolder.Drive.DifferentPlayerNameOnline ? SettingsHolder.Drive.PlayerNameOnline : SettingsHolder.Drive.PlayerName; if (result.Sessions?.Length == 1 && result.Sessions[0].Name == Game.TrackDaySessionName && result.Players?.Length > 1) { var session = result.Sessions[0]; var playerLaps = session.LapsTotalPerCar?[0] ?? 1; session.LapsTotalPerCar = session.LapsTotalPerCar?.Select(x => Math.Min(x, playerLaps)).ToArray(); session.Laps = session.Laps?.Where(x => x.LapId < playerLaps).ToArray(); session.BestLaps = session.BestLaps?.Select(x => { if (x.LapId < playerLaps) { return(x); } var best = session.Laps?.Where(y => y.CarNumber == x.CarNumber).MinEntryOrDefault(y => y.Time); if (best == null) { return(null); } return(new Game.ResultBestLap { Time = best.Time, LapId = best.LapId, CarNumber = x.CarNumber }); }).NonNull().ToArray(); } var dragExtra = result.GetExtraByType <Game.ResultExtraDrag>(); var sessionsData = result.Sessions?.Select(session => { int[] takenPlaces; SessionFinishedData data; if (dragExtra != null) { data = new DragFinishedData { BestReactionTime = dragExtra.ReactionTime, Total = dragExtra.Total, Wins = dragExtra.Wins, Runs = dragExtra.Runs, }; var delta = dragExtra.Wins * 2 - dragExtra.Runs; takenPlaces = new[] { delta >= 0 ? 0 : 1, delta <= 0 ? 0 : 1 }; } else { data = new SessionFinishedData(session.Name?.ApartFromLast(@" Session")); takenPlaces = session.GetTakenPlacesPerCar(); } var sessionBestLap = session.BestLaps?.MinEntryOrDefault(x => x.Time); var sessionBest = sessionBestLap?.Time; data.PlayerEntries = ( from player in result.Players let car = CarsManager.Instance.GetById(player.CarId ?? "") let carSkin = car?.GetSkinById(player.CarSkinId ?? "") select new { Player = player, Car = car, CarSkin = carSkin } ).Select((entry, i) => { var bestLapTime = session.BestLaps?.Where(x => x.CarNumber == i).MinEntryOrDefault(x => x.Time)?.Time; var laps = session.Laps?.Where(x => x.CarNumber == i).Select(x => new SessionFinishedData.PlayerLapEntry { LapNumber = x.LapId + 1, Sectors = x.SectorsTime, Cuts = x.Cuts, TyresShortName = x.TyresShortName, Total = x.Time, DeltaToBest = bestLapTime.HasValue ? x.Time - bestLapTime.Value : (TimeSpan?)null, DeltaToSessionBest = sessionBest.HasValue ? x.Time - sessionBest.Value : (TimeSpan?)null, }).ToArray(); var lapTimes = laps?.Skip(1).Select(x => x.Total.TotalSeconds).Where(x => x > 10d).ToList(); double?progress, spread; if (lapTimes == null || lapTimes.Count < 2) { progress = null; spread = null; } else { var firstHalf = lapTimes.Count / 2; var firstMedian = lapTimes.Take(firstHalf).Median(); var secondMedian = lapTimes.Skip(firstHalf).Median(); progress = 1d - secondMedian / firstMedian; spread = (lapTimes.Max() - lapTimes.Min()) / bestLapTime?.TotalSeconds; } return(new SessionFinishedData.PlayerEntry { Name = i == 0 ? playerName : entry.Player.Name, IsPlayer = i == 0, Index = i, Car = entry.Car, CarSkin = entry.CarSkin, TakenPlace = i < takenPlaces?.Length ? takenPlaces[i] + 1 : DefinitelyNonPrizePlace, PrizePlace = takenPlaces?.Length > 1, LapsCount = session.LapsTotalPerCar?.ArrayElementAtOrDefault(i) ?? 0, BestLapTime = bestLapTime, DeltaToSessionBest = sessionBestLap?.CarNumber == i ? null : bestLapTime - sessionBest, TotalTime = session.Laps?.Where(x => x.CarNumber == i).Select(x => x.SectorsTime.Sum()).Sum(), Laps = laps, LapTimeProgress = progress, LapTimeSpread = spread }); }).OrderBy(x => x.TakenPlace).ToList(); if (data.PlayerEntries.Count > 0) { var maxLaps = data.PlayerEntries.Select(x => x.Laps.Length).Max(); var bestTotalTime = data.PlayerEntries.Where(x => x.Laps.Length == maxLaps).MinEntryOrDefault(x => x.TotalTime ?? TimeSpan.MaxValue); foreach (var entry in data.PlayerEntries) { var lapsDelta = maxLaps - entry.Laps.Length; if (bestTotalTime == entry) { entry.TotalTimeDelta = "-"; } else if (lapsDelta > 0) { entry.TotalTimeDelta = $"+{lapsDelta} {PluralizingConverter.Pluralize(lapsDelta, "lap")}"; } else { var t = entry.TotalTime - bestTotalTime?.TotalTime; var v = t?.ToMillisecondsString(); entry.TotalTimeDelta = t == TimeSpan.Zero ? "" : v != null ? $"+{v}" : null; } } } var bestProgress = (from player in data.PlayerEntries where player.LapTimeProgress > 0.03 orderby player.LapTimeProgress descending select player).FirstOrDefault(); var bestConsistent = (from player in data.PlayerEntries where player.LapTimeSpread < 0.02 orderby player.LapTimeSpread descending select player).FirstOrDefault(); data.RemarkableNotes = new[] { sessionBestLap == null ? null : new SessionFinishedData.RemarkableNote("[b]Best lap[/b] made by ", data.PlayerEntries.GetByIdOrDefault(sessionBestLap.CarNumber), null), new SessionFinishedData.RemarkableNote("[b]The Best Off-roader Award[/b] goes to ", (from player in data.PlayerEntries let cuts = (double)player.Laps.Sum(x => x.Cuts) / player.Laps.Length where cuts > 1.5 orderby cuts descending select player).FirstOrDefault(), null), new SessionFinishedData.RemarkableNote("[b]Remarkable progress[/b] shown by ", bestProgress, null), new SessionFinishedData.RemarkableNote("[b]The most consistent[/b] is ", bestConsistent, null), }.Where(x => x?.Player != null).ToList(); return(data); }).ToList(); return(sessionsData?.Count == 1 ? (BaseFinishedData)sessionsData.First() : sessionsData?.Any() == true ? new SessionsFinishedData(sessionsData) : null); }
private static BaseFinishedData GetFinishedData(Game.StartProperties properties, Game.Result result) { var conditions = properties?.GetAdditional <PlaceConditions>(); var takenPlace = conditions?.GetTakenPlace(result) ?? PlaceConditions.UnremarkablePlace; Logging.Debug($"Place conditions: {conditions?.GetDescription()}, result: {result.GetDescription()}"); { var extra = result.GetExtraByType <Game.ResultExtraDrift>(); if (extra != null) { return(new DriftFinishedData { Points = extra.Points, MaxCombo = extra.MaxCombo, MaxLevel = extra.MaxLevel, TakenPlace = takenPlace }); } } { var extra = result.GetExtraByType <Game.ResultExtraTimeAttack>(); if (extra != null) { var bestLapTime = result.Sessions.SelectMany(x => from lap in x.BestLaps where lap.CarNumber == 0 select lap.Time).MinOrDefault(); return(new TimeAttackFinishedData { Points = extra.Points, Laps = result.Sessions.Sum(x => x.LapsTotalPerCar.FirstOrDefault()), BestLapTime = bestLapTime == TimeSpan.Zero ? (TimeSpan?)null : bestLapTime, TakenPlace = takenPlace }); } } { var extra = result.GetExtraByType <Game.ResultExtraBestLap>(); if (extra != null && extra.IsNotCancelled && result.Sessions.Length == 1 && result.Players.Length == 1) { var bestLapTime = result.Sessions.SelectMany(x => from lap in x.BestLaps where lap.CarNumber == 0 select lap.Time).MinOrDefault(); var sectorsPerSections = result.Sessions.SelectMany(x => from lap in x.Laps where lap.CarNumber == 0 select lap.SectorsTime).ToList(); var theoreticallLapTime = sectorsPerSections.FirstOrDefault()?.Select((x, i) => sectorsPerSections.Select(y => y[i]).Min()).Sum(); return(new HotlapFinishedData { Laps = result.Sessions.Sum(x => x.LapsTotalPerCar.FirstOrDefault()), BestLapTime = bestLapTime == TimeSpan.Zero ? (TimeSpan?)null : bestLapTime, TheoreticallLapTime = theoreticallLapTime, TakenPlace = takenPlace }); } } var isOnline = properties?.ModeProperties is Game.OnlineProperties; var playerName = isOnline && SettingsHolder.Drive.DifferentPlayerNameOnline ? SettingsHolder.Drive.PlayerNameOnline : SettingsHolder.Drive.PlayerName; var dragExtra = result.GetExtraByType <Game.ResultExtraDrag>(); var sessionsData = result.Sessions.Select(session => { int[] takenPlaces; SessionFinishedData data; if (dragExtra != null) { data = new DragFinishedData { BestReactionTime = dragExtra.ReactionTime, Total = dragExtra.Total, Wins = dragExtra.Wins, Runs = dragExtra.Runs, }; var delta = dragExtra.Wins * 2 - dragExtra.Runs; takenPlaces = new[] { delta >= 0 ? 0 : 1, delta <= 0 ? 0 : 1 }; } else { data = new SessionFinishedData(session.Name.ApartFromLast(@" Session")); takenPlaces = session.GetTakenPlacesPerCar(); } var sessionBestLap = session.BestLaps.MinEntryOrDefault(x => x.Time); var sessionBest = sessionBestLap?.Time; data.PlayerEntries = ( from player in result.Players let car = CarsManager.Instance.GetById(player.CarId) let carSkin = car.GetSkinById(player.CarSkinId) select new { Player = player, Car = car, CarSkin = carSkin } ).Select((entry, i) => { var bestLapTime = session.BestLaps.Where(x => x.CarNumber == i).MinEntryOrDefault(x => x.Time)?.Time; return(new SessionFinishedData.PlayerEntry { Name = i == 0 ? playerName : entry.Player.Name, IsPlayer = i == 0, Car = entry.Car, CarSkin = entry.CarSkin, TakenPlace = i < takenPlaces.Length ? takenPlaces[i] + 1 : DefinitelyNonPrizePlace, PrizePlace = takenPlaces.Length > 1, LapsCount = session.LapsTotalPerCar.ElementAtOrDefault(i), BestLapTime = bestLapTime, DeltaToSessionBest = sessionBestLap?.CarNumber == i ? null : bestLapTime - sessionBest, Total = session.Laps.Where(x => x.CarNumber == i).Select(x => x.Time).Sum(), Laps = session.Laps.Where(x => x.CarNumber == i).Select(x => new SessionFinishedData.PlayerLapEntry { LapNumber = x.LapId + 1, Sectors = x.SectorsTime, Total = x.Time, DeltaToBest = bestLapTime.HasValue ? x.Time - bestLapTime.Value : (TimeSpan?)null, DeltaToSessionBest = sessionBest.HasValue ? x.Time - sessionBest.Value : (TimeSpan?)null, }).ToArray() }); }).OrderBy(x => x.TakenPlace).ToList(); return(data); }).ToList(); return(sessionsData.Count == 1 ? (BaseFinishedData)sessionsData.First() : sessionsData.Any() ? new SessionsFinishedData(sessionsData) : null); }