Exemple #1
0
        public void SaveToDraftTimeline(
            string file,
            IList <CombatLog> combatLogs)
        {
            if (!combatLogs.Any())
            {
                return;
            }

            var outputTypes = new[]
            {
                LogTypes.CastStart,
                LogTypes.Action,
                LogTypes.Dialog,
                LogTypes.Added,
                LogTypes.Marker,
                LogTypes.Effect,
                LogTypes.NetworkAbility,
                LogTypes.NetworkAOEAbility,
            };

            var timeline = new TimelineModel();

            timeline.Zone         = combatLogs.First().Zone;
            timeline.Locale       = Settings.Default.FFXIVLocale;
            timeline.TimelineName = $"{timeline.Zone} draft timeline";
            timeline.Revision     = "draft";
            timeline.Description  =
                "自動生成によるドラフト版タイムラインです。タイムライン定義の作成にご活用ください。" + Environment.NewLine +
                "なお未編集のままで運用できるようには設計されていません。";

            foreach (var log in combatLogs.Where(x =>
                                                 outputTypes.Contains(x.LogType)))
            {
                var a = new TimelineActivityModel()
                {
                    Time        = log.TimeStampElapted,
                    Text        = log.Text,
                    SyncKeyword = log.SyncKeyword,
                };

                switch (log.LogType)
                {
                case LogTypes.CastStart:
                    a.Notice = $"次は、{log.Skill}。";
                    break;

                case LogTypes.Action:
                    // 構えのないアクションか?
                    if (!combatLogs.Any(x =>
                                        x.ID < log.ID &&
                                        x.Skill == log.Skill &&
                                        x.LogType == LogTypes.CastStart &&
                                        (log.TimeStamp - x.TimeStamp).TotalSeconds <= 12))
                    {
                        a.Notice = $"次は、{log.Skill}。";
                    }
                    else
                    {
                        continue;
                    }

                    break;

                case LogTypes.Added:
                    a.Notice = $"次は、{log.Actor}。";

                    if (timeline.Activities.Any(x =>
                                                x.Time == a.Time &&
                                                x.Text == a.Text &&
                                                x.SyncKeyword == a.SyncKeyword))
                    {
                        continue;
                    }

                    break;

                case LogTypes.Marker:
                case LogTypes.Effect:
                    a.Enabled = false;

                    if (timeline.Activities.Any(x =>
                                                x.Time == a.Time &&
                                                x.Text == a.Text))
                    {
                        continue;
                    }

                    break;

                case LogTypes.NetworkAbility:
                case LogTypes.NetworkAOEAbility:
                    a.Enabled = false;

                    if (timeline.Activities.Any(x =>
                                                x.Time == a.Time &&
                                                x.Text == a.Text))
                    {
                        continue;
                    }

                    break;
                }

                timeline.Add(a);
            }

            timeline.Save(file);
        }
Exemple #2
0
        private void NotifyActivity(
            TimelineActivityModel act)
        {
            if (string.IsNullOrEmpty(act.Name) &&
                string.IsNullOrEmpty(act.Text) &&
                string.IsNullOrEmpty(act.Notice))
            {
                act.IsNotified = true;
                return;
            }

            var now    = DateTime.Now;
            var offset = this.CurrentTime - act.Time;
            var log    =
                $"{TLSymbol} Notice from TL. " +
                $"name={act.Name}, text={act.TextReplaced}, notice={act.NoticeReplaced}, offset={offset.TotalSeconds:N1}";

            var notice = act.NoticeReplaced ?? string.Empty;

            notice = TimelineExpressionsModel.ReplaceText(notice);

            if (string.Equals(notice, "auto", StringComparison.OrdinalIgnoreCase))
            {
                notice = !string.IsNullOrEmpty(act.TextReplaced) ?
                         act.TextReplaced :
                         act.Name;

                if (offset.TotalSeconds <= -1.0)
                {
                    var offsetText = (offset.TotalSeconds * -1).ToString("N0");
                    notice += $" まで、あと{offsetText}秒";
                }

                if (!string.IsNullOrEmpty(notice))
                {
                    notice += "。";
                }
            }

            var isSync =
                (TimelineRazorModel.Instance?.SyncTTS ?? false) ||
                act.NoticeSync.Value;

            RaiseLog(log);
            NotifySoundAsync(notice, act.NoticeDevice.GetValueOrDefault(), isSync, act.NoticeVolume);

            var vnotices = act.VisualNoticeStatements
                           .Where(x => x.Enabled.GetValueOrDefault())
                           .Select(x => x.Clone());

            var inotices = act.ImageNoticeStatements
                           .Where(x => x.Enabled.GetValueOrDefault());

            if (!vnotices.Any() &&
                !inotices.Any())
            {
                return;
            }

            var placeholders = TimelineManager.Instance.GetPlaceholders();

            foreach (var v in vnotices)
            {
                // ソート用にログ番号を格納する
                // 優先順位は最後尾とする
                v.LogSeq    = long.MaxValue;
                v.Timestamp = DateTime.Now;

                switch (v.Text)
                {
                case TimelineVisualNoticeModel.ParentTextPlaceholder:
                    v.TextToDisplay = act.TextReplaced;
                    break;

                case TimelineVisualNoticeModel.ParentNoticePlaceholder:
                    v.TextToDisplay = act.NoticeReplaced;
                    break;

                default:
                    v.TextToDisplay = act.SyncMatch != null && act.SyncMatch.Success ?
                                      act.SyncMatch.Result(v.Text) :
                                      v.Text;
                    break;
                }

                if (string.IsNullOrEmpty(v.TextToDisplay))
                {
                    continue;
                }

                v.TextToDisplay = TimelineExpressionsModel.ReplaceText(v.TextToDisplay);

                // PC名をルールに従って置換する
                v.TextToDisplay = XIVPluginHelper.Instance.ReplacePartyMemberName(
                    v.TextToDisplay,
                    Settings.Default.PCNameInitialOnDisplayStyle);

                WPFHelper.BeginInvoke(async() =>
                {
                    if (v.Delay > 0)
                    {
                        await Task.Delay(TimeSpan.FromSeconds(v.Delay ?? 0));
                    }

                    TimelineNoticeOverlay.NoticeView?.AddNotice(v);
                    v.SetSyncToHide(placeholders);
                    v.AddSyncToHide();
                });
            }

            foreach (var i in inotices)
            {
                WPFHelper.BeginInvoke(async() =>
                {
                    if (i.Delay > 0)
                    {
                        await Task.Delay(TimeSpan.FromSeconds(i.Delay ?? 0));
                    }

                    i.StartNotice();
                    i.SetSyncToHide(placeholders);
                    i.AddSyncToHide();
                });
            }
        }