Example #1
0
        public (ISmartScriptLine[], IConditionLine[]) ToDatabaseCompatibleSmartScript(SmartScript script)
        {
            if (script.Events.Count == 0)
            {
                return(new ISmartScriptLine[0], null);
            }

            var  eventId         = 0;
            var  lines           = new List <ISmartScriptLine>();
            var  conditions      = new List <IConditionLine>();
            var  previousWasWait = false;
            long nextTriggerId   = script.Events.Where(e => e.Id == SmartConstants.EventTriggerTimed)
                                   .Select(e => e.GetParameter(0).Value)
                                   .DefaultIfEmpty(0)
                                   .Max() + 1;

            foreach (SmartEvent e in script.Events)
            {
                if (e.Actions.Count == 0)
                {
                    continue;
                }

                e.ActualId = eventId;

                for (var index = 0; index < e.Actions.Count; ++index)
                {
                    SmartEvent actualEvent = e;

                    if (previousWasWait)
                    {
                        actualEvent = smartFactory.EventFactory(SmartConstants.EventTriggerTimed);
                        actualEvent.GetParameter(0).Value = nextTriggerId++;
                    }
                    else if (index > 0)
                    {
                        actualEvent = smartFactory.EventFactory(SmartConstants.EventLink);
                    }

                    int linkTo = e.Actions.Count - 1 == index ? 0 : eventId + 1;

                    SmartAction actualAction = e.Actions[index].Copy();

                    if (actualAction.Id == SmartConstants.ActionWait)
                    {
                        linkTo = 0;
                        SmartAction waitAction = actualAction;
                        actualAction = smartFactory.ActionFactory(SmartConstants.ActionTriggerTimed,
                                                                  smartFactory.SourceFactory(SmartConstants.SourceNone),
                                                                  smartFactory.TargetFactory(SmartConstants.TargetNone));
                        actualAction.GetParameter(0).Value = nextTriggerId;
                        actualAction.GetParameter(1).Value = waitAction.GetParameter(0).Value;
                        actualAction.GetParameter(2).Value = waitAction.GetParameter(0).Value;
                        actualAction.Comment = SmartConstants.CommentWait;
                        previousWasWait      = true;
                    }
                    else
                    {
                        if (actualAction.Id == SmartConstants.ActionComment)
                        {
                            SmartAction commentAction = actualAction;
                            actualAction = smartFactory.ActionFactory(SmartConstants.ActionNone,
                                                                      smartFactory.SourceFactory(SmartConstants.SourceNone),
                                                                      smartFactory.TargetFactory(SmartConstants.TargetNone));
                            actualAction.Comment = commentAction.Comment;
                        }
                        previousWasWait = false;
                    }

                    var actionData = smartDataManager.GetRawData(SmartType.SmartAction, actualAction.Id);

                    if (actionData.TargetIsSource)
                    {
                        smartFactory.UpdateTarget(actualAction.Target, actualAction.Source.Id);
                        for (int i = 0; i < actualAction.Target.ParametersCount; ++i)
                        {
                            actualAction.Target.GetParameter(i).Copy(actualAction.Source.GetParameter(i));
                        }

                        smartFactory.UpdateSource(actualAction.Source, 0);
                    }

                    if (actionData.ImplicitSource != null)
                    {
                        smartFactory.UpdateSource(actualAction.Source, smartDataManager.GetDataByName(SmartType.SmartSource, actionData.ImplicitSource).Id);
                    }
                    else if (actionData.SourceStoreInAction)
                    {
                        actualAction.GetParameter(2).Value = actualAction.Source.Id;
                        actualAction.GetParameter(3).Value = actualAction.Source.GetParameter(0).Value;
                        actualAction.GetParameter(4).Value = actualAction.Source.GetParameter(1).Value;
                        actualAction.GetParameter(5).Value = actualAction.Source.GetParameter(2).Value;
                    }

                    SmartEvent eventToSerialize = actualEvent.ShallowCopy();
                    eventToSerialize.Parent = script;
                    eventToSerialize.Actions.Add(actualAction);

                    var serialized           = eventToSerialize.ToSmartScriptLines(script.EntryOrGuid, script.SourceType, eventId, linkTo);
                    var serializedConditions = actualEvent.ToConditionLines(script.EntryOrGuid, script.SourceType, eventId);

                    if (serialized.Length != 1)
                    {
                        throw new InvalidOperationException();
                    }

                    lines.Add(serialized[0]);
                    if (serializedConditions != null)
                    {
                        conditions.AddRange(serializedConditions);
                    }

                    eventId++;
                }
            }

            return(lines.ToArray(), conditions.ToArray());
        }
Example #2
0
        public (ISmartScriptLine[], IConditionLine[]) ToDatabaseCompatibleSmartScript(SmartScript script)
        {
            if (script.Events.Count == 0)
            {
                return(new ISmartScriptLine[0], null);
            }

            var  eventId         = 0;
            var  lines           = new List <ISmartScriptLine>();
            var  conditions      = new List <IConditionLine>();
            var  previousWasWait = false;
            long nextTriggerId   = script.Events.Where(e => e.Id == SmartConstants.EventTriggerTimed)
                                   .Select(e => e.GetParameter(0).Value)
                                   .DefaultIfEmpty(0)
                                   .Max() + 1;

            var usedTimedActionLists = script.Events
                                       .SelectMany(e => e.Actions)
                                       .Where(a => a.Id == SmartConstants.ActionCallTimedActionList ||
                                              a.Id == SmartConstants.ActionCallRandomTimedActionList ||
                                              a.Id == SmartConstants.ActionCallRandomRangeTimedActionList)
                                       .SelectMany(a =>
            {
                if (a.Id == SmartConstants.ActionCallRandomTimedActionList)
                {
                    return new int[]
                    {
                        (int)a.GetParameter(0).Value,
                        (int)a.GetParameter(1).Value,
                        (int)a.GetParameter(2).Value,
                        (int)a.GetParameter(3).Value,
                        (int)a.GetParameter(4).Value,
                        (int)a.GetParameter(5).Value,
                    }
                }
                ;
                if (a.Id == SmartConstants.ActionCallRandomRangeTimedActionList &&
                    a.GetParameter(1).Value - a.GetParameter(0).Value < 20)
                {
                    return(Enumerable.Range((int)a.GetParameter(0).Value, (int)(a.GetParameter(1).Value - a.GetParameter(0).Value + 1)));
                }
                return(new int[] { (int)a.GetParameter(0).Value });
            })
                                       .Where(id => id != 0)
                                       .ToHashSet();

            int firstUnusedActionList = Math.Abs(script.EntryOrGuid) * 100 - 1;

            int GetNextUnusedTimedActionList()
            {
                do
                {
                    firstUnusedActionList++;
                } while (usedTimedActionLists.Contains(firstUnusedActionList));

                usedTimedActionLists.Add(firstUnusedActionList);
                return(firstUnusedActionList);
            }

            foreach (var gv in script.GlobalVariables)
            {
                lines.Add(gv.ToMetaSmartScriptLine(script.EntryOrGuid, script.SourceType, eventId++));
            }

            if (script.SourceType == SmartScriptType.TimedActionList)
            {
                foreach (SmartEvent e in script.Events)
                {
                    for (var index = 0; index < e.Actions.Count; ++index)
                    {
                        SmartEvent eventToSerialize = index == 0 ? e.ShallowCopy() : smartFactory.EventFactory(SmartConstants.EventUpdateInCombat);

                        SmartAction actualAction = e.Actions[index].Copy();
                        AdjustCoreCompatibleAction(actualAction);

                        eventToSerialize.Parent = script;
                        eventToSerialize.Actions.Add(actualAction);

                        var serialized = eventToSerialize.ToSmartScriptLines(script.EntryOrGuid, script.SourceType, eventId++, false, 0);

                        if (serialized.Length != 1)
                        {
                            throw new InvalidOperationException();
                        }

                        lines.Add(serialized[0]);
                    }
                }
            }
            else
            {
                SmartEvent        originalEvent;
                List <SmartEvent> additionalEvents = new();

                void FlushLines(SmartEvent?eventForConditions)
                {
                    if (eventForConditions != null)
                    {
                        var serializedConditions = eventForConditions.ToConditionLines(SmartConstants.ConditionSourceSmartScript, script.EntryOrGuid, script.SourceType, eventId);
                        if (serializedConditions != null)
                        {
                            conditions.AddRange(serializedConditions);
                        }
                    }

                    foreach (var toSerialize in new SmartEvent[] { originalEvent }.Concat(additionalEvents))
                    {
                        if (toSerialize.Actions.Count == 0)
                        {
                            continue;
                        }
                        var serialized = toSerialize.ToSmartScriptLines(script.EntryOrGuid, script.SourceType, eventId, true);
                        eventId += serialized.Length;
                        lines.AddRange(serialized);
                    }
                    additionalEvents.ForEach(d => d.Actions.Clear());
                    originalEvent.Actions.Clear();
                }

                foreach (SmartEvent e in script.Events)
                {
                    if (e.Actions.Count == 0)
                    {
                        continue;
                    }

                    originalEvent        = e.ShallowCopy();
                    originalEvent.Parent = script;
                    additionalEvents.Clear();
                    SmartEvent lastEvent = originalEvent;

                    long accumulatedWaits = 0;
                    for (var index = 0; index < e.Actions.Count; ++index)
                    {
                        if (previousWasWait)
                        {
                            var eventTimed = smartFactory.EventFactory(SmartConstants.EventTriggerTimed);
                            eventTimed.Parent = script;
                            eventTimed.GetParameter(0).Value = nextTriggerId++;
                            additionalEvents.Add(eventTimed);
                            lastEvent = eventTimed;
                        }

                        if (e.Actions[index].Id == SmartConstants.ActionBeginInlineActionList ||
                            e.Actions[index].Id == SmartConstants.ActionAfter)
                        {
                            var         timedActionListId   = GetNextUnusedTimedActionList();
                            SmartAction callTimedActionList = smartFactory.ActionFactory(SmartConstants.ActionCallTimedActionList,
                                                                                         smartFactory.SourceFactory(SmartConstants.SourceSelf),
                                                                                         smartFactory.TargetFactory(SmartConstants.TargetSelf));
                            callTimedActionList.GetParameter(0).Value = timedActionListId;
                            if (e.Actions[index].Id == SmartConstants.ActionBeginInlineActionList)
                            {
                                callTimedActionList.GetParameter(1).Value = e.Actions[index].GetParameter(0).Value;
                                callTimedActionList.GetParameter(2).Value = e.Actions[index].GetParameter(1).Value;
                                index++;
                            }
                            callTimedActionList.Comment = SmartConstants.CommentInlineActionList;
                            lastEvent.AddAction(callTimedActionList);

                            FlushLines(e);

                            long afterTimeMin = 0;
                            long afterTimeMax = 0;
                            int  timedEventId = 0;
                            for (; index < e.Actions.Count; ++index)
                            {
                                if (e.Actions[index].Id == SmartConstants.ActionAfter || e.Actions[index].Id == SmartConstants.ActionWait)
                                {
                                    afterTimeMin += e.Actions[index].GetParameter(0).Value;
                                    afterTimeMax += e.Actions[index].GetParameter(1).Value;
                                    if (e.Actions[index].GetParameter(1).Value == 0)
                                    {
                                        afterTimeMax += e.Actions[index].GetParameter(0).Value;
                                    }
                                }
                                else if (e.Actions[index].Id == SmartConstants.ActionAfterMovement && index > 0)
                                {
                                    afterTimeMin = 0;
                                    afterTimeMax = 0;
                                    var pathId = e.Actions[index - 1].GetParameter(1).Value;
                                    timedActionListId = GetNextUnusedTimedActionList();

                                    var eventFinishedMovement =
                                        smartFactory.EventFactory(SmartConstants.EventWaypointsEnded);
                                    eventFinishedMovement.Parent = script;
                                    eventFinishedMovement.GetParameter(1).Value = pathId;

                                    var callAnotherTimedActionList = smartFactory.ActionFactory(SmartConstants.ActionCallTimedActionList,
                                                                                                smartFactory.SourceFactory(SmartConstants.SourceSelf),
                                                                                                smartFactory.TargetFactory(SmartConstants.TargetSelf));
                                    callAnotherTimedActionList.GetParameter(0).Value = timedActionListId;
                                    callAnotherTimedActionList.Comment = SmartConstants.CommentInlineMovementActionList;

                                    eventFinishedMovement.AddAction(callAnotherTimedActionList);
                                    additionalEvents.Add(eventFinishedMovement);
                                    FlushLines(null);
                                }
                                else
                                {
                                    SmartEvent after = smartFactory.EventFactory(SmartConstants.EventUpdateInCombat);
                                    after.GetParameter(0).Value = afterTimeMin;
                                    after.GetParameter(1).Value = afterTimeMax;
                                    SmartAction actualAction = e.Actions[index].Copy();
                                    AdjustCoreCompatibleAction(actualAction);

                                    after.Parent = new SmartScript(new SmartScriptSolutionItem(timedActionListId, SmartScriptType.TimedActionList), smartFactory, smartDataManager, messageBoxService);
                                    after.AddAction(actualAction);

                                    var serialized = after.ToSmartScriptLines(timedActionListId, SmartScriptType.TimedActionList, timedEventId++, false, 0);

                                    if (serialized.Length != 1)
                                    {
                                        throw new InvalidOperationException();
                                    }

                                    lines.Add(serialized[0]);
                                    afterTimeMin = 0;
                                    afterTimeMax = 0;
                                }
                            }
                        }
                        else if (e.Actions[index].Id == SmartConstants.ActionWait)
                        {
                            accumulatedWaits += e.Actions[index].GetParameter(0).Value;

                            if (index == e.Actions.Count - 1 || e.Actions[index + 1].Id == SmartConstants.ActionWait)
                            {
                                continue;
                            }

                            SmartAction createTimedAction = smartFactory.ActionFactory(SmartConstants.ActionCreateTimed,
                                                                                       smartFactory.SourceFactory(SmartConstants.SourceNone),
                                                                                       smartFactory.TargetFactory(SmartConstants.TargetNone));
                            createTimedAction.GetParameter(0).Value = nextTriggerId;
                            createTimedAction.GetParameter(1).Value = accumulatedWaits;
                            createTimedAction.GetParameter(2).Value = accumulatedWaits;
                            createTimedAction.Comment = SmartConstants.CommentWait;
                            previousWasWait           = true;

                            originalEvent.AddAction(createTimedAction);
                        }
                        else
                        {
                            previousWasWait = false;
                            SmartAction actualAction = e.Actions[index].Copy();
                            AdjustCoreCompatibleAction(actualAction);
                            lastEvent.AddAction(actualAction);
                        }
                    }

                    if (originalEvent.Actions.Count == 0)
                    {
                        continue;
                    }

                    FlushLines(e);
                }
            }

            return(lines.ToArray(), conditions.ToArray());
        }
        public static ISmartScriptLine[] ToWaitFreeSmartScriptLines(this SmartScript script, ISmartFactory smartFactory)
        {
            if (script.Events.Count == 0)
            {
                return(new ISmartScriptLine[0]);
            }

            int eventId = 0;
            List <ISmartScriptLine> lines = new List <ISmartScriptLine>();
            bool previousWasWait          = false;
            int  nextTriggerId            = script.Events.Where(e => e.Id == SmartConstants.EVENT_TRIGGER_TIMED).Select(e => e.GetParameter(0).Value).DefaultIfEmpty(0).Max() + 1;

            //@todo: don't use hardcoded IDs!!!!
            foreach (SmartEvent e in script.Events)
            {
                if (e.Actions.Count == 0)
                {
                    continue;
                }

                e.ActualId = eventId;

                for (int index = 0; index < e.Actions.Count; ++index)
                {
                    SmartEvent actualEvent = e;

                    if (previousWasWait)
                    {
                        actualEvent = smartFactory.EventFactory(SmartConstants.EVENT_TRIGGER_TIMED);
                        actualEvent.SetParameter(0, nextTriggerId++);
                    }
                    else if (index > 0)
                    {
                        actualEvent = smartFactory.EventFactory(SmartConstants.EVENT_LINK);
                    }

                    int linkTo = (e.Actions.Count - 1 == index ? 0 : eventId + 1);

                    SmartAction actualAction = e.Actions[index];

                    if (actualAction.Id == SmartConstants.ACTION_WAIT)
                    {
                        linkTo = 0;
                        SmartAction waitAction = actualAction;
                        actualAction = smartFactory.ActionFactory(SmartConstants.ACTION_TRIGGER_TIMED, smartFactory.SourceFactory(SmartConstants.SOURCE_NONE), smartFactory.TargetFactory(SmartConstants.TARGET_NONE));
                        actualAction.SetParameter(0, nextTriggerId);
                        actualAction.SetParameter(1, waitAction.GetParameter(0).GetValue());
                        actualAction.SetParameter(2, waitAction.GetParameter(0).GetValue());
                        actualAction.Comment = SmartConstants.COMMENT_WAIT;
                        previousWasWait      = true;
                    }
                    else
                    {
                        previousWasWait = false;
                    }

                    SmartEvent eventToSerialize = actualEvent.ShallowCopy();
                    eventToSerialize.Actions.Add(actualAction.Copy());

                    var serialized =
                        eventToSerialize.ToSmartScriptLines(script.EntryOrGuid, script.SourceType, eventId, linkTo);

                    if (serialized.Length != 1)
                    {
                        throw new InvalidOperationException();
                    }

                    lines.Add(serialized[0]);

                    eventId++;
                }
            }

            return(lines.ToArray());
        }
Example #4
0
        public (ISmartScriptLine[], IConditionLine[]) ToDatabaseCompatibleSmartScript(SmartScript script)
        {
            if (script.Events.Count == 0)
            {
                return(new ISmartScriptLine[0], null);
            }

            var  eventId         = 0;
            var  lines           = new List <ISmartScriptLine>();
            var  conditions      = new List <IConditionLine>();
            var  previousWasWait = false;
            long nextTriggerId   = script.Events.Where(e => e.Id == SmartConstants.EventTriggerTimed)
                                   .Select(e => e.GetParameter(0).Value)
                                   .DefaultIfEmpty(0)
                                   .Max() + 1;

            foreach (var gv in script.GlobalVariables)
            {
                lines.Add(gv.ToMetaSmartScriptLine(script.EntryOrGuid, script.SourceType, eventId++));
            }

            if (script.SourceType == SmartScriptType.TimedActionList)
            {
                foreach (SmartEvent e in script.Events)
                {
                    for (var index = 0; index < e.Actions.Count; ++index)
                    {
                        SmartEvent eventToSerialize = index == 0 ? e.ShallowCopy() : smartFactory.EventFactory(SmartConstants.EventUpdateInCombat);

                        SmartAction actualAction = e.Actions[index].Copy();
                        AdjustCoreCompatibleAction(actualAction);

                        eventToSerialize.Parent = script;
                        eventToSerialize.Actions.Add(actualAction);

                        var serialized = eventToSerialize.ToSmartScriptLines(script.EntryOrGuid, script.SourceType, eventId++, false, 0);

                        if (serialized.Length != 1)
                        {
                            throw new InvalidOperationException();
                        }

                        lines.Add(serialized[0]);
                    }
                }
            }
            else
            {
                foreach (SmartEvent e in script.Events)
                {
                    if (e.Actions.Count == 0)
                    {
                        continue;
                    }

                    SmartEvent originalEvent = e.ShallowCopy();
                    originalEvent.Parent = script;
                    List <SmartEvent> delayedWaits = new();
                    SmartEvent        lastEvent    = originalEvent;

                    long accumulatedWaits = 0;
                    for (var index = 0; index < e.Actions.Count; ++index)
                    {
                        if (previousWasWait)
                        {
                            var eventTimed = smartFactory.EventFactory(SmartConstants.EventTriggerTimed);
                            eventTimed.Parent = script;
                            eventTimed.GetParameter(0).Value = nextTriggerId++;
                            delayedWaits.Add(eventTimed);
                            lastEvent = eventTimed;
                        }

                        if (e.Actions[index].Id == SmartConstants.ActionWait)
                        {
                            accumulatedWaits += e.Actions[index].GetParameter(0).Value;

                            if (index == e.Actions.Count - 1 || e.Actions[index + 1].Id == SmartConstants.ActionWait)
                            {
                                continue;
                            }

                            SmartAction createTimedAction = smartFactory.ActionFactory(SmartConstants.ActionCreateTimed,
                                                                                       smartFactory.SourceFactory(SmartConstants.SourceNone),
                                                                                       smartFactory.TargetFactory(SmartConstants.TargetNone));
                            createTimedAction.GetParameter(0).Value = nextTriggerId;
                            createTimedAction.GetParameter(1).Value = accumulatedWaits;
                            createTimedAction.GetParameter(2).Value = accumulatedWaits;
                            createTimedAction.Comment = SmartConstants.CommentWait;
                            previousWasWait           = true;

                            originalEvent.AddAction(createTimedAction);
                        }
                        else
                        {
                            previousWasWait = false;
                            SmartAction actualAction = e.Actions[index].Copy();
                            AdjustCoreCompatibleAction(actualAction);
                            lastEvent.AddAction(actualAction);
                        }
                    }

                    if (originalEvent.Actions.Count == 0)
                    {
                        continue;
                    }

                    var serializedConditions = e.ToConditionLines(SmartConstants.ConditionSourceSmartScript, script.EntryOrGuid, script.SourceType, eventId);
                    if (serializedConditions != null)
                    {
                        conditions.AddRange(serializedConditions);
                    }

                    foreach (var toSerialize in new SmartEvent[] { originalEvent }.Concat(delayedWaits))
                    {
                        var serialized = toSerialize.ToSmartScriptLines(script.EntryOrGuid, script.SourceType, eventId, true);
                        eventId += serialized.Length;
                        lines.AddRange(serialized);
                    }
                }
            }

            return(lines.ToArray(), conditions.ToArray());
        }
Example #5
0
        public SmartScriptEditorViewModel(IHistoryManager history,
                                          IDatabaseProvider database,
                                          IEventAggregator eventAggregator,
                                          ISmartDataManager smartDataManager,
                                          ISmartFactory smartFactory,
                                          IItemFromListProvider itemFromListProvider,
                                          ISmartTypeListProvider smartTypeListProvider,
                                          IStatusBar statusbar,
                                          ISolutionItemNameRegistry itemNameRegistry)
        {
            this.history               = history;
            this.database              = database;
            this.smartDataManager      = smartDataManager;
            this.smartFactory          = smartFactory;
            this.itemFromListProvider  = itemFromListProvider;
            this.smartTypeListProvider = smartTypeListProvider;
            this.statusbar             = statusbar;
            this.itemNameRegistry      = itemNameRegistry;

            EditEvent       = new DelegateCommand(EditEventCommand);
            DeselectActions = new DelegateCommand(() =>
            {
                foreach (var e in Events)
                {
                    if (!e.IsSelected)
                    {
                        foreach (var a in e.Actions)
                        {
                            a.IsSelected = false;
                        }
                    }
                }
            });
            DeselectAll = new DelegateCommand(() =>
            {
                foreach (var e in Events)
                {
                    foreach (var a in e.Actions)
                    {
                        a.IsSelected = false;
                    }
                    e.IsSelected = false;
                }
            });
            DeselectAllEvents = new DelegateCommand(() =>
            {
                foreach (var e in Events)
                {
                    e.IsSelected = false;
                }
            });
            OnDropItems = new DelegateCommand <int?>(destIndex =>
            {
                using (script.BulkEdit("Reorder events"))
                {
                    var selected = new List <SmartEvent>();
                    int d        = destIndex.Value;
                    for (int i = Events.Count - 1; i >= 0; --i)
                    {
                        if (Events[i].IsSelected)
                        {
                            if (i <= destIndex)
                            {
                                d--;
                            }
                            selected.Add(Events[i]);
                            script.Events.RemoveAt(i);
                        }
                    }
                    if (d == -1)
                    {
                        d = 0;
                    }
                    selected.Reverse();
                    foreach (var s in selected)
                    {
                        script.Events.Insert(d++, s);
                    }
                }
            });
            OnDropActions = new DelegateCommand <DropActionsArgs>(data =>
            {
                using (script.BulkEdit("Reorder actions"))
                {
                    var selected = new List <SmartAction>();
                    var d        = data.ActionIndex;
                    for (var eventIndex = 0; eventIndex < Events.Count; eventIndex++)
                    {
                        var e = Events[eventIndex];
                        for (int i = e.Actions.Count - 1; i >= 0; --i)
                        {
                            if (e.Actions[i].IsSelected)
                            {
                                if (eventIndex == data.EventIndex && i < data.ActionIndex)
                                {
                                    d--;
                                }
                                selected.Add(e.Actions[i]);
                                e.Actions.RemoveAt(i);
                            }
                        }
                    }
                    selected.Reverse();
                    foreach (var s in selected)
                    {
                        Events[data.EventIndex].Actions.Insert(d++, s);
                    }
                }
            });
            EditAction = new DelegateCommand <SmartAction>(action => EditActionCommand(action));
            AddEvent   = new DelegateCommand(AddEventCommand);
            AddAction  = new DelegateCommand <NewActionViewModel>(AddActionCommand);

            SaveCommand = new AsyncAutoCommand(SaveAllToDb, null, e =>
            {
                statusbar.PublishNotification(new PlainNotification(NotificationType.Error, "Error while saving script to the database: " + e.Message));
            });

            DeleteAction   = new DelegateCommand <SmartAction>(DeleteActionCommand);
            DeleteSelected = new DelegateCommand(() =>
            {
                if (anyEventSelected)
                {
                    using (script.BulkEdit("Delete events"))
                    {
                        int?nextSelect = firstSelectedIndex;
                        if (multipleEventsSelected)
                        {
                            nextSelect = null;
                        }

                        for (int i = Events.Count - 1; i >= 0; --i)
                        {
                            if (Events[i].IsSelected)
                            {
                                Events.RemoveAt(i);
                            }
                        }

                        if (nextSelect.HasValue)
                        {
                            if (nextSelect.Value < Events.Count)
                            {
                                Events[nextSelect.Value].IsSelected = true;
                            }
                            else if (nextSelect.Value - 1 >= 0 && nextSelect.Value - 1 < Events.Count)
                            {
                                Events[nextSelect.Value - 1].IsSelected = true;
                            }
                        }
                    }
                }
                else if (anyActionSelected)
                {
                    using (script.BulkEdit("Delete actions"))
                    {
                        (int eventIndex, int actionIndex)? nextSelect = firstSelectedActionIndex;
                        if (multipleActionsSelected)
                        {
                            nextSelect = null;
                        }

                        for (int i = 0; i < Events.Count; ++i)
                        {
                            var e = Events[i];
                            for (int j = e.Actions.Count - 1; j >= 0; --j)
                            {
                                if (e.Actions[j].IsSelected)
                                {
                                    e.Actions.RemoveAt(j);
                                }
                            }
                        }

                        if (nextSelect.HasValue && nextSelect.Value.actionIndex < Events[nextSelect.Value.eventIndex].Actions.Count)
                        {
                            Events[nextSelect.Value.eventIndex].Actions[nextSelect.Value.actionIndex].IsSelected = true;
                        }
                    }
                }
            });

            UndoCommand = new DelegateCommand(history.Undo, () => history.CanUndo);
            RedoCommand = new DelegateCommand(history.Redo, () => history.CanRedo);

            EditSelected = new DelegateCommand(() =>
            {
                if (anyEventSelected)
                {
                    if (!multipleEventsSelected)
                    {
                        EditEventCommand();
                    }
                }
                else if (anyActionSelected && !multipleActionsSelected)
                {
                    EditActionCommand(Events[firstSelectedActionIndex.eventIndex]
                                      .Actions[firstSelectedActionIndex.actionIndex]);
                }
            });

            CopyCommand = new DelegateCommand(() =>
            {
                var selectedEvents = Events.Where(e => e.IsSelected).ToList();
                if (selectedEvents.Count > 0)
                {
                    var lines = string.Join("\n",
                                            selectedEvents.SelectMany((e, index) => e.ToSmartScriptLines(script.EntryOrGuid, script.SourceType, index)).Select(s => s.ToSqlString()));
                    Clipboard.SetText(lines);
                }
                else
                {
                    var selectedActions = Events.SelectMany(e => e.Actions).Where(e => e.IsSelected).ToList();
                    if (selectedActions.Count > 0)
                    {
                        var fakeEvent = new SmartEvent(-1)
                        {
                            ReadableHint = ""
                        };
                        foreach (var a in selectedActions)
                        {
                            fakeEvent.AddAction(a.Copy());
                        }
                        var lines = string.Join("\n", fakeEvent.ToSmartScriptLines(script.EntryOrGuid, script.SourceType, 0).Select(s => s.ToSqlString()));
                        Clipboard.SetText(lines);
                    }
                }
            });
            CutCommand = new DelegateCommand(() =>
            {
                CopyCommand.Execute();
                DeleteSelected.Execute();
            });
            PasteCommand = new DelegateCommand(() =>
            {
                var lines = (Clipboard.GetText() ?? "").Split('\n').Select(line =>
                {
                    if (line.TryToISmartScriptLine(out var s))
                    {
                        return(s);
                    }
                    return(null);
                }).Where(l => l != null).ToList();
                if (lines.Count > 0)
                {
                    if (lines[0].EventType == -1) // actions
                    {
                        int?eventIndex  = null;
                        int?actionIndex = null;
                        using (script.BulkEdit("Paste actions"))
                        {
                            for (int i = 0; i < Events.Count - 1; ++i)
                            {
                                if (Events[i].IsSelected)
                                {
                                    eventIndex = i;
                                }

                                for (int j = Events[i].Actions.Count - 1; j >= 0; j--)
                                {
                                    if (Events[i].Actions[j].IsSelected)
                                    {
                                        eventIndex = i;
                                        if (!actionIndex.HasValue)
                                        {
                                            actionIndex = j;
                                        }
                                        else
                                        {
                                            actionIndex--;
                                        }
                                        //Events[i].Actions.RemoveAt(j);
                                    }
                                }
                            }

                            if (!eventIndex.HasValue)
                            {
                                eventIndex = Events.Count - 1;
                            }

                            if (eventIndex < 0)
                            {
                                return;
                            }

                            if (!actionIndex.HasValue)
                            {
                                actionIndex = Events[eventIndex.Value].Actions.Count - 1;
                            }

                            if (actionIndex < 0)
                            {
                                actionIndex = 0;
                            }

                            DeselectAll.Execute();
                            foreach (var smartAction in lines.Select(line => script.SafeActionFactory(line)))
                            {
                                Events[eventIndex.Value].Actions.Insert(actionIndex.Value, smartAction);
                                smartAction.IsSelected = true;
                                actionIndex++;
                            }
                        }
                    }
                    else
                    {
                        int?index = null;
                        using (script.BulkEdit("Paste events"))
                        {
                            for (int i = Events.Count - 1; i >= 0; --i)
                            {
                                if (Events[i].IsSelected)
                                {
                                    if (!index.HasValue)
                                    {
                                        index = i;
                                    }
                                    else
                                    {
                                        index--;
                                    }
                                    //Events.RemoveAt(i);
                                }
                            }
                            if (!index.HasValue)
                            {
                                index = Events.Count;
                            }
                            script.InsertFromClipboard(index.Value, lines);
                        }
                    }
                }
            });

            Action <bool, int> selectionUpDown = (addToSelection, diff) =>
            {
                if (anyEventSelected)
                {
                    var selectedEventIndex = Math.Clamp(firstSelectedIndex + diff, 0, Events.Count - 1);
                    if (!addToSelection)
                    {
                        DeselectAll.Execute();
                    }
                    Events[selectedEventIndex].IsSelected = true;
                }
                else if (anyActionSelected)
                {
                    var nextActionIndex = firstSelectedActionIndex.actionIndex + diff;
                    var nextEventIndex  = firstSelectedActionIndex.eventIndex;
                    while (nextActionIndex == -1 || nextActionIndex >= Events[nextEventIndex].Actions.Count)
                    {
                        nextEventIndex += diff;
                        if (nextEventIndex >= 0 && nextEventIndex < Events.Count)
                        {
                            nextActionIndex = diff > 0 ? (Events[nextEventIndex].Actions.Count > 0 ? 0 : -1) : Events[nextEventIndex].Actions.Count - 1;
                        }
                        else
                        {
                            break;
                        }
                    }

                    if (nextActionIndex != -1 && nextEventIndex >= 0 && nextEventIndex < Events.Count)
                    {
                        DeselectAll.Execute();
                        Events[nextEventIndex].Actions[nextActionIndex].IsSelected = true;
                    }
                }
                else
                {
                    if (Events.Count > 0)
                    {
                        Events[diff > 0 ? 0 : Events.Count - 1].IsSelected = true;
                    }
                }
            };

            SelectionUp   = new DelegateCommand <bool?>(addToSelection => selectionUpDown(addToSelection ?? false, -1));
            SelectionDown = new DelegateCommand <bool?>(addToSelection => selectionUpDown(addToSelection ?? false, 1));
            SelectionLeft = new DelegateCommand(() =>
            {
                if (!anyEventSelected && anyActionSelected)
                {
                    var actionEventIndex = firstSelectedActionIndex;
                    DeselectAll.Execute();
                    Events[actionEventIndex.eventIndex].IsSelected = true;
                }
                else if (!anyEventSelected && !anyActionSelected)
                {
                    selectionUpDown(false, -1);
                }
            });
            SelectionRight = new DelegateCommand(() =>
            {
                if (!anyEventSelected)
                {
                    selectionUpDown(false, -1);
                }
                if (anyEventSelected)
                {
                    var eventIndex = firstSelectedIndex;
                    if (Events[eventIndex].Actions.Count > 0)
                    {
                        DeselectAll.Execute();
                        Events[eventIndex].Actions[0].IsSelected = true;
                    }
                }
            });

            SelectAll = new DelegateCommand(() =>
            {
                foreach (var e in Events)
                {
                    e.IsSelected = true;
                }
            });

            this.history.PropertyChanged += (sender, args) =>
            {
                UndoCommand.RaiseCanExecuteChanged();
                RedoCommand.RaiseCanExecuteChanged();
            };

            token = eventAggregator.GetEvent <EventRequestGenerateSql>().Subscribe((args) =>
            {
                if (args.Item is SmartScriptSolutionItem)
                {
                    var itemm = args.Item as SmartScriptSolutionItem;
                    if (itemm.Entry == _item.Entry && itemm.SmartType == _item.SmartType)
                    {
                        args.Sql = new SmartScriptExporter(script, smartFactory).GetSql();
                    }
                }
            });
        }