Beispiel #1
0
        public void Set_LogicVariableShouldReturnTrue()
        {
            var lv = new LogicVariable {
                Value = true
            };

            Assert.True(lv.Value);
        }
Beispiel #2
0
        public void AddVariable_ShouldAddName()
        {
            CombinatorialCircuit c = new CombinatorialCircuit();
            LogicVariable        a = new LogicVariable {
                Name = "x1"
            };

            bool result = c.AddVariable(a);

            Assert.True(result, "Should add variable name.");
        }
        public bool AddVariable(LogicVariable newLv)
        {
            LogicVariable lv;

            if (_lv.TryGetValue(newLv.Name, out lv))
            {
                return(false);
            }
            _lv.Add(newLv.Name, newLv);
            return(true);
        }
Beispiel #4
0
        public void GetLogicVariableByName_ShouldGetSameLogicVariable()
        {
            // We can use 'var' as an implicit type letting the compiler
            // determines and assign the most appropriate type
            var c = new CombinatorialCircuit();
            var a = new LogicVariable {
                Name = "x1"
            };

            c.AddVariable(a);
            Assert.Same(a, c.GetLogicVariableByName("x1"));
        }
Beispiel #5
0
    void DoNextAction()
    {
        var actionVar = new LogicVariable("Action");

        var beforeBytes = GC.GetTotalMemory(false);
        var action      = this.SolveFor(actionVar, new Structure(SNextAction, actionVar));
        var allocBytes  = GC.GetTotalMemory(false) - beforeBytes;

        if (allocBytes > 0)
        {
            DecisionCycleAlloc = (int)allocBytes;
        }
        InitiateAction(action);
    }
Beispiel #6
0
 private void MouseSelectionChanged(GameObject newSelection)
 {
     MouseSelection = newSelection;
     if (MouseSelection != null)
     {
         captionStyle.normal.textColor = Color.white;
         var cap = new LogicVariable("Caption");
         caption =
             new GUIContent(
                 (string)KnowledgeBase.Global.SolveFor(cap, new Structure("caption", MouseSelection, cap), this));
         captionSize = captionStyle.CalcSize(caption);
     }
     TryCompletionIfCompleteWord();
 }
Beispiel #7
0
        public void AddVariable_ShouldFailAddDuplicateName()
        {
            CombinatorialCircuit c = new CombinatorialCircuit();
            LogicVariable        a = new LogicVariable {
                Name = "x2"
            };
            LogicVariable b = new LogicVariable {
                Name = "x2"
            };

            c.AddVariable(a);
            bool result = c.AddVariable(b);

            Assert.False(result, "Should fail add duplicate variable name.");
        }
        public object CheckPlan(object head)
        {
            var full = new LogicVariable("Full");

            try
            {
                myKB.SolveFor(full, new Structure("check_plan", head, full), this);
            }
            catch (System.Exception)
            {
                return(false);
            }

            return(full);
        }
Beispiel #9
0
        public object Activate(object name)
        {
            LogicVariable conditions = new LogicVariable("Conditions");

            try
            {
                myKB.SolveFor(conditions, new Structure("activate", name, conditions), this);
            }
            catch (System.Exception ex)
            {
                return(false);
            }

            return(conditions);
        }
Beispiel #10
0
        public object Use(object name)
        {
            LogicVariable plan = new LogicVariable("Plan");

            try
            {
                myKB.SolveFor(plan, new Structure("use", name, plan), this);
            }
            catch (System.Exception ex)
            {
                return(false);
            }

            return(plan);
        }
Beispiel #11
0
        public void Execute(LogicExecuteMethodInformation executeMethodInformation, LogicVariable variable)
        {
            object value;

            if (this.abj != null)
            {
                value = this.abj.Execute(executeMethodInformation);
            }
            else
            {
                value = null;
            }
            FieldInfo field = executeMethodInformation.LogicClassType.GetField(variable.VariableName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);

            field.SetValue(executeMethodInformation.LogicEntityObject, value);
        }
Beispiel #12
0
        public override object Execute(LogicExecuteMethodInformation executeMethodInformation)
        {
            if (string.IsNullOrEmpty(this.abm))
            {
                Log.Error("Get Variable: variableName not defined");
                return(null);
            }
            object        obj            = null;
            LogicVariable variableByName = base.ParentMethod.ParentClass.GetVariableByName(this.abm);

            if (variableByName != null)
            {
                if (base.DotPathAction != null && base.DotPathAction is LogicAssignVariableAction)
                {
                    ((LogicAssignVariableAction)base.DotPathAction).Execute(executeMethodInformation, variableByName);
                    return(null);
                }
                FieldInfo field = executeMethodInformation.LogicClassType.GetField(variableByName.VariableName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
                obj = field.GetValue(executeMethodInformation.LogicEntityObject);
            }
            LogicLocalVariable logicLocalVariable = null;

            if (variableByName == null)
            {
                logicLocalVariable = executeMethodInformation.GetLocalVariable(this.abm);
                if (logicLocalVariable != null)
                {
                    if (base.DotPathAction != null && base.DotPathAction is LogicAssignVariableAction)
                    {
                        ((LogicAssignVariableAction)base.DotPathAction).Execute(executeMethodInformation, logicLocalVariable);
                        return(null);
                    }
                    obj = logicLocalVariable.Value;
                }
            }
            if (variableByName == null && logicLocalVariable == null)
            {
                Log.Error("Get Variable: variable not exists \"{0}\"", this.abm);
                return(null);
            }
            if (base.DotPathAction != null)
            {
                obj = base.DotPathAction.Execute(executeMethodInformation, obj);
            }
            return(obj);
        }
Beispiel #13
0
    PieMenu MakeMenu(GameObject selection)
    {
        var tags      = new List <string>();
        var actions   = new List <object>();
        var stringVar = new LogicVariable("Tag");
        var actionVar = new LogicVariable("Action");
        var goal      = new Structure("menu_item", selection, stringVar, actionVar);

        // ReSharper disable once UnusedVariable
#pragma warning disable 168
        foreach (var ignore in gameObject.KnowledgeBase().Prove(goal))
#pragma warning restore 168
        {
            tags.Add((string)stringVar.Value);
            actions.Add(Term.CopyInstantiation(actionVar));
        }

        return(new PieMenu(tags, actions, MenuGUIStyle, 50, SimController.GreyOutTexture));
    }
Beispiel #14
0
        public override Type GetReturnType()
        {
            if (!string.IsNullOrEmpty(this.VariableName))
            {
                LogicVariable variableByName = base.ParentMethod.ParentClass.GetVariableByName(this.VariableName);
                if (variableByName != null)
                {
                    return(variableByName.VariableType);
                }
            }
            List <LogicLocalVariable> accessedLocalVariables = base.ParentMethod.GetAccessedLocalVariables(this);

            foreach (LogicLocalVariable current in accessedLocalVariables)
            {
                if (current.Name == this.VariableName)
                {
                    return(current.Type);
                }
            }
            return(null);
        }
Beispiel #15
0
            void Init()
            {
                int    index = 0;
                string oper  = "";

                while (index < m_Expression.Length)
                {
                    char c = m_Expression[index];
                    ++index;
                    if (c == '=')
                    {
                        oper += c;
                        if (oper == "==" || oper == "!=" || oper == ">=" || oper == "<=")
                        {
                            m_Operation = oper;
                        }
                    }
                    else if (c == '!' || c == '>' || c == '<')
                    {
                        oper       += c;
                        m_Operation = oper;
                    }
                    else
                    {
                        oper = "";
                    }
                }
                if (string.IsNullOrEmpty(m_Operation))
                {
                    throw new Exception("m_Operation error");
                }
                string[] e = m_Expression.Split(new string[] { m_Operation }, StringSplitOptions.RemoveEmptyEntries);
                if (e.Length != 2)
                {
                    throw new Exception("vars error");
                }
                m_Left  = new LogicVariable(e[0]);
                m_Right = new LogicVariable(e[1]);
            }
Beispiel #16
0
    private void TryCompletion()
    {
        var  completionVar     = new LogicVariable("Output");
        var  dialogActVar      = new LogicVariable("DialogAct");
        bool completionSuccess = false;

        try
        {
            completionSuccess = this.IsTrue("input_completion", this.input, completionVar, dialogActVar);
        }
        catch (InferenceStepsExceededException e)
        {
            Debug.LogError("Completion took too many steps for input: " + this.input);
            Debug.LogException(e);
        }
        if (completionSuccess)
        {
            this.completion = (string)completionVar.Value;
            this.dialogAct  = Term.CopyInstantiation(dialogActVar.Value);
            if (this.IsTrue("well_formed_dialog_act", this.dialogAct))
            {
                this.formatted = this.completion == "" ?
                                 string.Format("<b><color=lime>{0}</color></b>", this.input)
                    : string.Format("<color=lime>{0}{1}<i>{2}</i></color>",
                                    this.input,
                                    (this.input.EndsWith(" ") || this.input.EndsWith("'") ||
                                     !char.IsLetterOrDigit(this.completion[0]))
                                    ? "" : " ",
                                    this.completion);
                var da = this.dialogAct as Structure;
                if (da != null && da.Arity > 1)
                {
                    var a = da.Argument <GameObject>(1);
                    this.commentary = string.Format("{0} to {1}\n{2}", da.Functor, (a == this) ? "myself" : a.name,
                                                    ISOPrologWriter.WriteToString(dialogActVar.Value));
                }
                else
                {
                    this.commentary = ISOPrologWriter.WriteToString(dialogActVar.Value);
                }
            }
            else
            {
                // Input is grammatical but not well formed.
                this.formatted = this.completion == "" ?
                                 string.Format("<b><color=yellow>{0}</color></b>", this.input)
                    : string.Format("<color=yellow>{0}{1}</color><color=grey><i>{2}</i></color>",
                                    this.input,
                                    (this.input.EndsWith(" ") || !char.IsLetterOrDigit(this.completion[0])) ? "" : " ",
                                    this.completion);
                if (this.completion == "")
                {
                    this.commentary = string.Format(
                        "This input is grammatical, but doesn't make sense to me\n{0}",
                        ISOPrologWriter.WriteToString(dialogActVar.Value));
                }
                else
                {
                    this.commentary = "This is grammatical but nonsensical\n" + ISOPrologWriter.WriteToString(dialogActVar.Value);
                }
            }
        }
        else
        {
            this.formatted  = string.Format("<color=red>{0}</color>", this.input);
            this.commentary = "Sorry; I don't understand any sentences beginning with those words.";
        }
    }
Beispiel #17
0
    private void TryCompletion()
    {
        // Update the mouse selection, so Prolog can get at it.
        mouseSelectionELNode.StoreExclusive(MouseSelection, true);

        var  completionVar     = new LogicVariable("Output");
        var  dialogActVar      = new LogicVariable("DialogAct");
        bool completionSuccess = false;

        try
        {
            completionSuccess = this.IsTrue("input_completion", input, completionVar, dialogActVar);
        }
        catch (InferenceStepsExceededException e)
        {
            Debug.LogError("Completion took too many steps for input: " + input);
            Debug.LogException(e);
        }
        if (completionSuccess)
        {
            completion = (string)completionVar.Value;
            dialogAct  = Term.CopyInstantiation(dialogActVar.Value);
            if (this.IsTrue("well_formed_dialog_act", dialogAct))
            {
                formatted = completion == "" ?
                            string.Format("<b><color=lime>{0}</color></b>", input)
                    : string.Format("<color=lime>{0}{1}<i>{2}</i></color>",
                                    input,
                                    (input.EndsWith(" ") || input.EndsWith("'") ||
                                     !char.IsLetterOrDigit(completion[0]))
                                    ? "" : " ",
                                    completion);

                var da = dialogAct as Structure;
                if (da != null && da.Arity > 1)
                {
                    var a         = da.Argument <GameObject>(1);
                    var addressee = (a == gameObject) ? "myself" : a.name;
                    commentary = string.Format("{0} to {1}\n{2}", da.Functor, addressee,
                                               ISOPrologWriter.WriteToString(dialogActVar.Value));
                    formatted = string.Format("{1} (speaking to {0})", addressee, formatted);
                }
                else
                {
                    commentary = ISOPrologWriter.WriteToString(dialogActVar.Value);
                }
            }
            else
            {
                // Input is grammatical but not well formed.
                formatted = completion == "" ?
                            string.Format("<b><color=yellow>{0}</color></b>", input)
                    : string.Format("<color=yellow>{0}{1}</color><color=grey><i>{2}</i></color>",
                                    input,
                                    (input.EndsWith(" ") || !char.IsLetterOrDigit(completion[0])) ? "" : " ",
                                    completion);
                if (completion == "")
                {
                    commentary = string.Format(
                        "This input is grammatical, but doesn't make sense to me\n{0}",
                        ISOPrologWriter.WriteToString(dialogActVar.Value));
                }
                else
                {
                    commentary = "This is grammatical but nonsensical\n" + ISOPrologWriter.WriteToString(dialogActVar.Value);
                }
            }
        }
        else
        {
            var lastWordOfInput = LastWordOfInput;
            if (lastWordOfInput != "" && Prolog.Prolog.IsPrefixOfDistinctLexicalItem(lastWordOfInput))
            {
                FormatInputWithoutColorCoding();
            }
            else
            {
                FormatRejectionOfInput();
            }
        }
    }
Beispiel #18
0
 public abstract bool BindsVar(LogicVariable v);
Beispiel #19
0
        private static void Main(string[] args)
        {
            // NOTE: No error handling etc. is included here, this sample is just intended to give you a starting point on
            // handling zenon Logic projects via code,
            // IMPORTANT: To avoid side effects, you should make sure that the Logic workbench is not running,
            // which is not shown here.

            // This sample accesses zenon via COM, therefore we need to connect first.
            var zenonEditor = Marshal.GetActiveObject(ZenonRuntimeComObjectName) as zenOn.ApplicationED;

            if (zenonEditor == null)
            {
                Console.WriteLine("Cannot connect to an instance of zenon Editor.");
                return;
            }

            // The active zenon editor project is used for our sample.
            var zenonProject = zenonEditor.MyWorkspace.ActiveDocument;

            if (zenonProject == null)
            {
                Console.WriteLine("No active instance of a zenon Editor project can be received.");
                return;
            }

            // NOTE: For this example, you need a reference to zenon.Interop.dll in your .csproj.
            // We added it from version 7.60 to a binaries folder.
            //
            // You can use alternative approaches to the one which is shown here, i.e.:
            // - modifying the project as pure XML
            //   Required:      References to zenonApi.Core and zenonApi.Logic.
            //   Advantage:     No dependency on Windows or zenon.
            //   Disadvantage:  If you want to import the object model to Logic, you need to do this on your own.
            // - modifying the project via a COM reference to zenon, as done in this example
            //   Required:      Reference to zenon.Interop.dll, references to zenonApi.Core, zenonApi.Logic and zenonApi.Zenon
            //   Advantage:     Easy to import and modify Logic projects from within a zenon context.
            //   Disadvantage:  Can only be done with a running zenon Editor instance on Windows
            // - modifying the project not via the Add-In framework
            //   Required:      Reference to Scada.AddIn.Contracts, zenonApi.Core, zenonApi.Logic, zenonApi.Zenon
            //   Advantage:     Same as for COM
            //   Disadvantage:  Same as for COM
            // - Just create projects and do basic modifications without any of our APIs
            //   Required:      -
            //   Advantage:     No dependencies, except K5B.exe and/or K5Prp.dll
            //   Disadvantage:  Just XML, no typed object model, hard to modify/maintain, etc.
            // What you choose simply depends on what you are developing and using.
            // The easiest way might be to work with the provided APIs we use here for COM and Add-In.

            // If you use the Add-In Framework, use "new zenonApi.Zenon.Zenon(zenonProject)
            var wrapper = new zenonApi.Zenon.ZenonCom(zenonProject);

            // We want to modify or create a Logic project named "Sample":
            var lazyLogicProjects       = wrapper.LazyLogicProjects;
            var sampleProjectToBeEdited = lazyLogicProjects.FirstOrDefault(x => x.ProjectName == "Sample")?.Value;

            if (sampleProjectToBeEdited == null)
            {
                // "Sample" does not exist, we need to create it with the following.
                // All changes you make in the API will only take affect, after you call ImportLogicProjectsIntoZenon
                // (see the end of this file)
                sampleProjectToBeEdited = new LogicProject("Sample");
                lazyLogicProjects.Add(new LazyLogicProject(sampleProjectToBeEdited));
            }

            // Access the logic options etc. via a object model. The following shows some examples.
            sampleProjectToBeEdited.Settings.TriggerTime.CycleTime = 10000;
            sampleProjectToBeEdited.Settings.CompilerSettings.CompilerOptions["warniserr"] = "OFF";

            // Get the first global variable group ("(GLOBAL)" and "(RETAIN)" always exist).
            var variableGroup = sampleProjectToBeEdited.GlobalVariables.VariableGroups.FirstOrDefault();

            // The appropriate group can also be accessed directly like this:
            variableGroup = sampleProjectToBeEdited.GlobalVariables[LogicVariableKind.Global];

            // Sample for creating some string variables in our "Sample" project:
            for (int i = 0; i < 10; i++)
            {
                var variableSample = new LogicVariable()
                {
                    InitialValue    = "5",
                    MaxStringLength = "255",
                    Type            = "STRING",
                    Name            = "MyVariable" + i,
                };
                variableSample.VariableInfos.Add(new LogicVariableInfo()
                {
                    // Set to be visible in zenon (SYB Flag)
                    Data = "<syb>",
                    Type = LogicVariableInformationTypeKind.Embed
                });

                variableSample.VariableInfos.Add(new LogicVariableInfo()
                {
                    Data = "STRATON",
                    Type = LogicVariableInformationTypeKind.Profile
                });

                variableGroup.Variables.Add(variableSample);
            }

            // Get the first folder of your application tree in Logic and rename it
            LogicFolder folder = sampleProjectToBeEdited.ApplicationTree.Folders.FirstOrDefault();

            if (folder == null)
            {
                // Does not exist, create it instead.
                folder = new LogicFolder("RenamedTestFolder");
                sampleProjectToBeEdited.ApplicationTree.Folders.Add(folder);
            }

            // Renaming is possible.
            folder.Name = "RenamedTestFolder";

            // Same for the first program:
            LogicProgram program = folder.Programs.FirstOrDefault();

            if (program == null)
            {
                program = new LogicProgram("RenamedTestProgram");
                folder.Programs.Add(program);
            }
            program.Name = "RenamedMyProgram";
            // Modify the source code of a program:
            program.SourceCode += "\n// Some Comment";

            // Navigate back to the application tree when only having the program (useful when working with multiple logic
            // projects at once):
            var folderAgain = program.Parent;

            // Change the cycle timing and other project settings
            sampleProjectToBeEdited.Settings.TriggerTime.CycleTime = 12345;
            sampleProjectToBeEdited.Settings.CompilerSettings.CompilerOptions["warniserr"] = "OFF";

            // Modify variables (if it exists)
            var variable = program.VariableGroups.FirstOrDefault()?.Variables.FirstOrDefault();

            if (variable != null)
            {
                variable.Name           = "RenamedVariable";
                variable.Attributes.In  = true;
                variable.Attributes.Out = true;
                variable.VariableInfos.Add(new LogicVariableInfo()
                {
                    Type = LogicVariableInformationTypeKind.Embed, Data = "<syb>"
                });
            }

            // Remove a folder if it exists
            sampleProjectToBeEdited.ApplicationTree.Folders.FirstOrDefault(x => x.Name == "Signals")?.Remove();

            // Sample for exporting a project object model to a file:
            string sampleFile = $@"C:\Users\{Environment.UserName}\Desktop\DemoProjectModified.xml";

            sampleProjectToBeEdited.ExportAsFile(sampleFile, Encoding.GetEncoding("iso-8859-1"));

            // Sample for reading a project object model from a file:
            var projectFromXmlFile = LogicProject.Import(XElement.Load(sampleFile));

            // Sample for convert the project object model to XElements and save it manually to the same file
            XElement modifiedProject = sampleProjectToBeEdited.ExportAsXElement();

            XDocument document = new XDocument
            {
                Declaration = new XDeclaration("1.0", "iso-8859-1", "yes")
            };

            document.Add(modifiedProject);
            using (XmlTextWriter writer = new XmlTextWriter(
                       $@"C:\Users\{Environment.UserName}\Desktop\DemoProjectModified.xml",
                       Encoding.GetEncoding("iso-8859-1")))
            {
                writer.Indentation = 3;
                writer.Formatting  = Formatting.Indented;
                document.Save(writer);
            }

            // Import and commit logic projects with the changes we made:
            wrapper.ImportLogicProjectsIntoZenon();

            // For zenon version 10 or higher, additional import options are available, e.g.:
            // wrapper.ImportLogicProjectsIntoZenon(true, ImportOptions.ReCreateVariables | ImportOptions.ApplyOnlineSettings);

            wrapper.Dispose();
        }
Beispiel #20
0
 public abstract bool BindsVar(LogicVariable v);
Beispiel #21
0
    private void InitiateAction(object action)
    {
        if (action == null)
        {
            return;
        }

        var actionCopy = Term.CopyInstantiation(action);

        ELNode.Store(motorRoot / SLastAction % actionCopy);

        var structure = action as Structure;

        if (structure != null)
        {
            switch (structure.Functor.Name)
            {
            case "face":
                Face(structure.Argument <GameObject>(0));
                break;

            case "say":
                // Say a fixed string
                Say(structure.Argument <string>(0), gameObject);
                break;

            case "cons":
                // It's a list of actions to initiate.
                InitiateAction(structure.Argument(0));
                InitiateAction(structure.Argument(1));
                break;

            case "pause":
                pauseUntil = Time.time + Convert.ToSingle(structure.Argument(0));
                break;

            case "pickup":
            {
                var patient = structure.Argument <GameObject>(0);
                if (patient == gameObject)
                {
                    throw new InvalidOperationException(name + ": tried to pickup() self!");
                }
                if (patient == gameObject)
                {
                    return;
                }
                if (patient == null)
                {
                    throw new NullReferenceException("Argument to pickup is not a gameobject");
                }
                var physob = patient.GetComponent <PhysicalObject>();
                if (physob == null)
                {
                    throw new NullReferenceException("Argument to pickup is not a physical object.");
                }
                physob.MoveTo(gameObject);
                break;
            }

            case "ingest":
            {
                var patient = structure.Argument <GameObject>(0);
                if (patient == null)
                {
                    throw new NullReferenceException("Argument to ingest is not a gameobject");
                }
                var physob = patient.GetComponent <PhysicalObject>();
                if (physob == null)
                {
                    throw new NullReferenceException("Argument to ingest is not a physical object.");
                }
                physob.Destroy();
                // TODO: FIX LOCATION UPDATE SO WE DON'T NEED TO KLUGE THIS
                locationRoot.DeleteKey(patient);
                var propinfo = patient.GetComponent <PropInfo>();
                if (propinfo != null)
                {
                    if (propinfo.IsFood)
                    {
                        physiologicalStates.DeleteKey(Symbol.Intern("hungry"));
                    }
                    if (propinfo.IsBeverage)
                    {
                        physiologicalStates.DeleteKey(Symbol.Intern("thirsty"));
                    }
                }
                break;
            }

            case "putdown":
            {
                var patient = structure.Argument <GameObject>(0);
                if (patient == gameObject)
                {
                    throw new InvalidOperationException(name + ": tried to putdown() self!");
                }
                if (patient == null)
                {
                    throw new NullReferenceException("Argument to putdown is not a gameobject");
                }
                var physob = patient.GetComponent <PhysicalObject>();
                if (physob == null)
                {
                    throw new NullReferenceException("Argument to putdown is not a physical object.");
                }
                var dest = structure.Argument <GameObject>(1);
                if (dest == null)
                {
                    throw new NullReferenceException("Argument to putdown is not a gameobject");
                }
                physob.MoveTo(dest);
                break;
            }

            case "flash":
            {
                flashColorA    = structure.Argument <Color>(0);
                flashColorB    = structure.Argument <Color>(1);
                flashPeriod    = Convert.ToSingle(structure.Argument(2));
                flashStartTime = Time.time;
                flashEndTime   = flashStartTime + Convert.ToSingle(structure.Argument(3));
                break;
            }

            case "get_in":
                GetIn(structure.Argument <GameObject>(0));
                break;

            case "dismount":
                Dismount();
                break;

            case "end_game":
                Application.Quit();
                break;

            default:
                // Assume it's dialog
                this.IsTrue("log_dialog_act", structure);
                GameObject thisAddressee =
                    ((structure.Arity >= 2) ?
                     structure.Argument(1) as GameObject
                            : gameObject) ?? gameObject;
                var talkingToSelf = thisAddressee == gameObject;
                if (!talkingToSelf || ShowMentalMonologue)
                {
                    var    textVar = new LogicVariable("DialogText");
                    object text    = null;
                    try
                    {
                        text = gameObject.SolveFor(textVar, "generate_text", structure, textVar);
                    }
                    catch (Exception e)
                    {
                        Debug.LogError(string.Format("Exception while generating text for {0}", gameObject.name));
                        Debug.LogException(e);
                    }
                    var textString = text as string;
                    if (textString == null)
                    {
                        throw new Exception(
                                  "generate_text returned " + ISOPrologWriter.WriteToString(text) + " for "
                                  + ISOPrologWriter.WriteToString(structure));
                    }
                    var talkingToPlayer = structure.Arity >= 2 &&
                                          ReferenceEquals(structure.Argument(1), playerSymbol);
                    SetSpeechTimeout(textString);
                    if (talkingToPlayer)
                    // Character is talking to zhimself
                    {
                        if (nlPrompt != null)
                        {
                            nlPrompt.OutputToPlayer(textString);
                        }
                        else
                        {
                            Say(string.Format("({0})", textString), thisAddressee);
                        }
                    }
                    else
                    {
                        Say(textString, thisAddressee);
                    }

                    if (!talkingToPlayer && !talkingToSelf)
                    {
                        // Tell the other characters
                        foreach (var node in socialSpace.Children)
                        {
                            var character = (GameObject)(node.Key);
                            if (character != gameObject)
                            {
                                character.QueueEvent((Structure)Term.CopyInstantiation(structure));
                            }
                        }
                        // TODO: fix it so that when characters appear, the system computes their social
                        // spaces from scratch.  Then we won't need this kluge.
                        if (!socialSpace.ContainsKey(thisAddressee))
                        {
                            thisAddressee.QueueEvent((Structure)Term.CopyInstantiation(structure));
                        }
                    }
                }
                break;
            }
            if (structure.Functor.Name != "pause")
            {
                // Report back to the character that the action has occurred.
                QueueEvent(structure);
            }
        }
        else
        {
            throw new InvalidOperationException("Unknown action: " + ISOPrologWriter.WriteToString(action));
        }
    }