public override void HandleNewRule(DialogEngine engine, DialogRule rule, List <string> extractedRefs) { var conds = rule.Conditions.ToList(); var alreadyReplaced = new List <string>(); for (var i = 0; i < conds.Count; i++) { var cond = conds[i]; // try replacing left side... var leftRefs = cond.Left.ExtractReferences().ToList(); if (leftRefs.Count == 1 && _nameToSet.ContainsKey(leftRefs[0])) { if (alreadyReplaced.Contains(leftRefs[0])) { throw new Exception($"Invalid condition set usage. The condition set, {leftRefs[0]} has already been process for {rule.Name}, and doing so again would cause an infinite loop of darkness and despair."); } alreadyReplaced.Add(leftRefs[0]); conds.RemoveAt(i); _nameToSet[leftRefs[0]].ForEach(c => conds.Add(c)); i = 0; } } rule.Conditions = conds.ToArray(); base.HandleNewRule(engine, rule, extractedRefs); }
public void ExecuteRuleOutcomes(DialogRule rule) { var exceptions = new List <Exception>(); for (var i = 0; i < rule.Outcomes.Length; i++) { try { var transform = BuildTransformFunction(); var outcome = rule.Outcomes[i]; if (outcome.Command.Equals("pass")) { continue; // ignore this. } //var targetAttribute = _attributes.g var transformedTargetName = transform(outcome.Target.ToLower()).ToLower(); var targetAttribute = _attributes.FirstOrDefault(a => a.Name.ToLower().Equals(transformedTargetName)); if (targetAttribute == null) { throw new Exception("Couldnt execute rule, because target attribute couldnt be found. " + outcome.Target + " as " + transformedTargetName); } var values = GetAttributeActualValues(); switch (outcome.Command) { case "set": var value = outcome.Arguments[""].ProcessAsPrefixMathTyped(values, transform); targetAttribute.Invoke(value); break; case "run": var outputValues = new Dictionary <string, object>(); foreach (var kv in outcome.Arguments) { outputValues.Add(kv.Key, kv.Value.ProcessAsPrefixMathTyped(values, transform)); } targetAttribute.Invoke(outputValues); break; case "pass": // do nothing break; default: throw new NotImplementedException("Unknown outcome command " + outcome.Command); } } catch (Exception ex) { exceptions.Add(ex); } } if (exceptions.Count > 0) { var allMessages = string.Join("\n", exceptions.Select(e => e.Message)); throw new Exception($"Failed to run all outcomes! {allMessages}"); } }
public List <string> ExtractReferencesFromRule(DialogRule rule) { var references = new List <string>(); for (var i = 0; i < rule.Conditions?.Length; i++) { references.AddRange(rule.Conditions[i].Left.ExtractReferences()); references.AddRange(rule.Conditions[i].Right.ExtractReferences()); } //for (var i = 0; i < rule.Dialog?.Length; i++) //{ // rule.Dialog[i].ContentParts.Select(p => p.ExtractReferences()).ToList() // .ForEach(refs => references.AddRange(refs)); // //references.AddRange(rule.Dialog[i].Content.ExtractReferences()); //} for (var i = 0; i < rule?.Outcomes?.Length; i++) { if (rule?.Outcomes[i]?.Command != "pass") { references.AddRange(rule.Outcomes[i].Target.ExtractReferences()); rule.Outcomes[i].Arguments.Values.Select(v => v.ExtractReferences()) .ToList().ForEach(refs => references.AddRange(refs)); } //references.AddRange(rule.Outcomes[i].Arguments.) } return(references.Distinct().ToList()); }
public void SimpleEngineConMath() { var player = new Actor(); player.Ammo = 3; var rules = new DialogRule[] { new DialogRule() { Name = "I have more than half health", Conditions = new DialogRule.DialogCondition[] { new DialogRule.DialogCondition() { Left = "player.health", Op = ">", Right = "(/ player.maxHealth 2)" } } }, new DialogRule() { Name = "I am the king of health and ammo", Conditions = new DialogRule.DialogCondition[] { new DialogRule.DialogCondition() { Left = "player.health", Op = "=", Right = "player.maxHealth" }, new DialogRule.DialogCondition() { Left = "player.ammo", Op = ">", Right = "25" } } } }; var attributes = new ObjectDialogAttribute[] { new ObjectDialogAttribute(player, "player", "health"), new ObjectDialogAttribute(player, "player", "maxHealth"), new ObjectDialogAttribute(player, "player", "ammo"), }; var engine = new DialogEngine(); rules.ToList().ForEach(r => engine.AddRule(r)); attributes.ToList().ForEach(a => engine.AddAttribute(a)); var best = engine.GetBestValidDialog(); Assert.IsNotNull(best); Assert.AreEqual("I have more than half health", best.Name); }
public void SimpleTemplateInterp() { var player = new Actor(); var rules = new DialogRule[] { new DialogRule() { Name = "I have full health!", Conditions = new DialogRule.DialogCondition[] { new DialogRule.DialogCondition() { Left = "player.health", Op = "=", Right = "player.maxHealth" } }, Dialog = new DialogRule.DialogPart[] { new DialogRule.DialogPart() { Speaker = "player", Content = "I have health of {player health} which and {player maxHealth + player health}", ContentParts = new string[] { "'I have health of '", "player.health", "' which and '", "(+ player.maxHealth player.health)" } } } }, }; var attributes = new ObjectDialogAttribute[] { new ObjectDialogAttribute(player, "player", "health"), new ObjectDialogAttribute(player, "player", "maxHealth"), new ObjectDialogAttribute(player, "player", "ammo"), }; var engine = new DialogEngine(); rules.ToList().ForEach(r => engine.AddRule(r)); attributes.ToList().ForEach(a => engine.AddAttribute(a)); var best = engine.GetBestValidDialog(); Assert.IsNotNull(best); Assert.AreEqual("I have full health!", best.Name); var dialogs = engine.ExecuteRuleDialogs(best); Assert.AreEqual(1, dialogs.Length); Assert.AreEqual("I have health of 50 which and 100", dialogs[0]); }
public void BoolBag2() { var player = new { health = 10, flags = new BagBoolElement[] { new BagBoolElement() { name = "a.part", value = true } }.ToList() }; var rules = new DialogRule[] { new DialogRule() { Name = "I have full health!", Conditions = new DialogRule.DialogCondition[] { new DialogRule.DialogCondition() { Left = "player.flags.a.part", Op = "=", Right = "true" }, new DialogRule.DialogCondition() { Left = "player.flags.b", Op = "=", Right = "false" } } }, }; var engine = new DialogEngine() .AddHandler(new BagBoolHandler()); var attributes = new DialogAttribute[] { new ObjectDialogAttribute(player, "player", "health"), DialogAttribute.New("player.flags", false, player.flags).UpdateElements(engine) //new BagDialogAttribute<bool>("player.flags", player.flags).UpdateElements(engine) }; attributes.ToList().ForEach(a => engine.AddAttribute(a)); rules.ToList().ForEach(r => engine.AddRule(r)); var best = engine.GetBestValidDialog(); Assert.IsNotNull(best); Assert.AreEqual("I have full health!", best.Name); }
public string[] ExecuteRuleSpeakers(DialogRule rule) { var values = GetAttributeActualValues(); var transform = BuildTransformFunction(); return(rule.Dialog .Select(d => String.Join("", d.Speaker.ProcessAsPrefixMathTyped(values, transform))) .ToArray()); }
public void SimpleEngineOutcomeSetter() { var player = new Actor(); player.MaxHealth = 100; player.Health = 100; var rules = new DialogRule[] { new DialogRule() { Name = "I have full health!", Conditions = new DialogRule.DialogCondition[] { new DialogRule.DialogCondition() { Left = "player.health", Op = "=", Right = "player.maxHealth" } }, Outcomes = new DialogRule.DialogOutcome[] { new DialogRule.DialogOutcome() { Command = "set", Target = "player.health", Arguments = new Dictionary <string, string>() { { "", "(/ player.maxHealth 2)" } } } } } }; var attributes = new ObjectDialogAttribute[] { new ObjectDialogAttribute(player, "player", "health"), new ObjectDialogAttribute(player, "player", "maxHealth"), new ObjectDialogAttribute(player, "player", "ammo"), }; var engine = new DialogEngine(); rules.ToList().ForEach(r => engine.AddRule(r)); attributes.ToList().ForEach(a => engine.AddAttribute(a)); var best = engine.GetBestValidDialog(); Assert.IsNotNull(best); Assert.AreEqual("I have full health!", best.Name); engine.ExecuteRuleOutcomes(best); Assert.AreEqual(50, player.Health); }
public void TemplateInterpStrings() { var player = new Actor(); var rules = new DialogRule[] { new DialogRule() { Name = "I have full health!", Conditions = new DialogRule.DialogCondition[] { new DialogRule.DialogCondition() { Left = "player.health", Op = "=", Right = "player.maxHealth" } }, Dialog = new DialogRule.DialogPart[] { new DialogRule.DialogPart() { Speaker = "player", Content = "my health is <color='red'> great </color>", ContentParts = new string[] { "'my health is <color='red'> great </color>'", } } } }, }; var attributes = new ObjectDialogAttribute[] { new ObjectDialogAttribute(player, "player", "health"), new ObjectDialogAttribute(player, "player", "maxHealth"), new ObjectDialogAttribute(player, "player", "ammo"), }; var engine = new DialogEngine(); rules.ToList().ForEach(r => engine.AddRule(r)); attributes.ToList().ForEach(a => engine.AddAttribute(a)); var best = engine.GetBestValidDialog(); Assert.IsNotNull(best); Assert.AreEqual("I have full health!", best.Name); var dialogs = engine.ExecuteRuleDialogs(best); Assert.AreEqual(1, dialogs.Length); Assert.AreEqual("my health is <color='red'> great </color>", dialogs[0]); }
public void IntBag() { var player = new { health = 10, ints = new BagIntElement[] { }.ToList() }; var rules = new DialogRule[] { new DialogRule() { Name = "I have full health!", Conditions = new DialogRule.DialogCondition[] { new DialogRule.DialogCondition() { Left = "player.ints.a", Op = "=", Right = "10" }, new DialogRule.DialogCondition() { Left = "player.ints.hidaldo.rep", Op = ">", Right = "6" } } }, }; var engine = new DialogEngine() .AddHandler(new BagIntHandler()); var attributes = new DialogAttribute[] { new ObjectDialogAttribute(player, "player", "health"), DialogAttribute.New("player.ints", 10, player.ints).UpdateElements(engine) //new BagDialogAttribute<bool>("player.flags", player.flags).UpdateElements(engine) }; attributes.ToList().ForEach(a => engine.AddAttribute(a)); rules.ToList().ForEach(r => engine.AddRule(r)); var best = engine.GetBestValidDialog(); Assert.IsNotNull(best); Assert.AreEqual("I have full health!", best.Name); }
public override void HandleNewRule(DialogEngine engine, DialogRule rule, List <string> extractedRefs) { //if (rule.Name.Equals("Rule Introduce Yourself Chief Alchemist Vol")) //{ // Console.WriteLine("FOUND SPECIAL RULE"); // Console.WriteLine(rule.Name); // Console.WriteLine("Extracted Refs "); // extractedRefs.ForEach(r => Console.WriteLine("\t" + r)); //} HandleRefs(engine, extractedRefs); base.HandleNewRule(engine, rule, extractedRefs); }
public DialogEngine AddRule(DialogRule rule) { var refs = ExtractReferencesFromRule(rule); for (var i = 0; i < _onAdditionHandlers.Count; i++) { _onAdditionHandlers[i].HandleNewRule(this, rule, refs); } // extract any references // TODO add optimization; if we have already seen a reference go by, never find it again. It has already been placed into the correct bag. // if any refs match bag prefix, //var bagAttrs = _attributes // .OfType<BagDialogAttribute>() // .ToList(); //for (var i = 0; i < refs.Count; i++) //{ // var bestAttr = default(BagDialogAttribute); // for (var b = 0; b < bagAttrs.Count; b ++) // { // if (refs[i].StartsWith(bagAttrs[b].Name) && (bestAttr == null || bagAttrs[b].Name.Length >= bestAttr.Name.Length)) // { // bestAttr = bagAttrs[b]; // } // } // if (bestAttr != null) // { // bestAttr.Add(this, new BagElement() // { // name = refs[i].Substring(bestAttr.Name.Length + 1), // value = false // }); // } //} _rules.Add(rule); return(this); }
public void SimpleEngineTransform() { var player = new Actor(); var rules = new DialogRule[] { new DialogRule() { Name = "I have full health!", Conditions = new DialogRule.DialogCondition[] { new DialogRule.DialogCondition() { Left = "dialog.target.health", Op = "=", Right = "player.maxHealth" } } } }; var attributes = new ObjectDialogAttribute[] { new ObjectDialogAttribute(player, "player", "health"), new ObjectDialogAttribute(player, "player", "maxHealth"), new ObjectDialogAttribute(player, "player", "ammo"), }; var engine = new DialogEngine() .AddTransform("dialog.target", () => "player"); rules.ToList().ForEach(r => engine.AddRule(r)); attributes.ToList().ForEach(a => engine.AddAttribute(a)); var best = engine.GetBestValidDialog(); Assert.IsNotNull(best); Assert.AreEqual("I have full health!", best.Name); }
public virtual void HandleNewRule(DialogEngine engine, DialogRule rule, List <string> extractedRefs) { }
public void SimpleEngineWithConditionSetLoopDetected() { var player = new Actor(); player.Health = player.MaxHealth; var sets = new DialogConditionSet[] { new DialogConditionSet() { Name = "test", Conditions = new DialogConditionSet.DialogCondition[] { new DialogConditionSet.DialogCondition() { Left = "player.health", Op = ">", Right = "1" }, new DialogConditionSet.DialogCondition() { Left = "__.conditions.egg", Op = "=", Right = "true" } } }, new DialogConditionSet() { Name = "egg", Conditions = new DialogConditionSet.DialogCondition[] { new DialogConditionSet.DialogCondition() { Left = "__.conditions.test", Op = "=", Right = "true" }, new DialogConditionSet.DialogCondition() { Left = "player.ammo", Op = ">", Right = "5" } } } }; var rules = new DialogRule[] { new DialogRule() { Name = "I have full health!", Conditions = new DialogRule.DialogCondition[] { new DialogRule.DialogCondition() { Left = "player.health", Op = "=", Right = "player.maxHealth" }, new DialogRule.DialogCondition() { Left = "__.conditions.egg", Op = "=", Right = "true" } } }, new DialogRule() { Name = "I am less specific", Conditions = new DialogRule.DialogCondition[] { new DialogRule.DialogCondition() { Left = "player.health", Op = "=", Right = "player.maxHealth" }, new DialogRule.DialogCondition() { Left = "player.health", Op = "=", Right = "player.maxHealth" } } }, }; var attributes = new ObjectDialogAttribute[] { new ObjectDialogAttribute(player, "player", "health"), new ObjectDialogAttribute(player, "player", "maxHealth"), new ObjectDialogAttribute(player, "player", "ammo"), }; var engine = new DialogEngine().AddHandler(new ConditionSetEvalHandler()); sets.ToList().ForEach(r => engine.AddConditionSet(r)); rules.ToList().ForEach(r => engine.AddRule(r)); attributes.ToList().ForEach(a => engine.AddAttribute(a)); var best = engine.GetBestValidDialog(); Assert.IsNotNull(best); Assert.AreEqual("I have full health!", best.Name); }
public void AsInTitle() { var src = @" an assist displayAs tunafish rep conditions player x is ‘mr vol’ dialogs :player1 muffin ducker outcomes set x to y"; var rules = new DialogRule[] { new DialogRule() { Name = "an assist", DisplayAs = "tunafish rep", Conditions = new DialogRule.DialogCondition[] { new DialogRule.DialogCondition() { Op = "=", Left = "player.x", Right = "'mr vol'" } }, Dialog = new DialogRule.DialogPart[] { new DialogRule.DialogPart() { Speaker = "'player1'", Content = "muffin ducker", ContentParts = new string[] { "'muffin ducker'", } } }, Outcomes = new DialogRule.DialogOutcome[] { new DialogRule.DialogOutcome() { Command = "set", Target = "x", Arguments = new Dictionary <string, string>() { { "", "y" } } } } } }; var bundle = new DialogBundle() { Name = "test", Rules = rules, ConditionSets = new DialogConditionSet[] { } }; var expected = JsonConvert.SerializeObject(bundle, Formatting.None, new JsonSerializerSettings() { StringEscapeHandling = StringEscapeHandling.Default }); var program = new WordLangResults(src); Assert.AreEqual(false, program.ParserErrors.AnyErrors); var v = new ProgramToJson(); var output = v.Visit(program.ProgramContext); Assert.IsNotNull(output); var backwards = JsonConvert.DeserializeObject <DialogBundle>(output); Assert.AreEqual(backwards, bundle); Assert.AreEqual(expected, output); }
public void SimpleJSON() { var src = @" tunafish conditions a is b a nifty rule displayAs tunafish rep conditions player health + 50 > 100 player x is ‘okay’ use tunafish dialogs :player1 speaking {player health + 12} line text :{player2.name} something <b>meaningful</b> :player3 this is <color='red'> red text </color> outcomes set x to y run actions.fart with power as 100 * player.fart with target as enemy"; var rules = new DialogRule[] { new DialogRule() { Name = "a nifty rule", DisplayAs = "tunafish rep", Conditions = new DialogRule.DialogCondition[] { new DialogRule.DialogCondition() { Op = ">", Left = "(+ player.health 50)", Right = "100" }, new DialogRule.DialogCondition() { Op = "=", Left = "player.x", Right = "'okay'" }, new DialogRule.DialogCondition() { Op = "=", Left = "__.conditions.tunafish", Right = "true" } }, Dialog = new DialogRule.DialogPart[] { new DialogRule.DialogPart() { Speaker = "'player1'", Content = "speaking {player health + 12} line text", ContentParts = new string[] { "'speaking '", "(+ player.health 12)", "' line text'" } }, new DialogRule.DialogPart() { Speaker = "player2.name", Content = "something <b>meaningful</b>", ContentParts = new string[] { "'something <b>meaningful</b>'" } }, new DialogRule.DialogPart() { Speaker = "'player3'", Content = "this is <color='red'> red text </color>", ContentParts = new string[] { "'this is <color=\\'red\\'> red text </color>'" } } }, Outcomes = new DialogRule.DialogOutcome[] { new DialogRule.DialogOutcome() { Command = "set", Target = "x", Arguments = new Dictionary <string, string>() { { "", "y" } } }, new DialogRule.DialogOutcome() { Command = "run", Target = "actions.fart", Arguments = new Dictionary <string, string>() { { "power", "(* 100 player.fart)" }, { "target", "enemy" } } } } } }; var bundle = new DialogBundle() { Name = "test", Rules = rules, ConditionSets = new DialogConditionSet[] { new DialogConditionSet() { Name = "tunafish", Conditions = new DialogConditionSet.DialogCondition[] { new DialogConditionSet.DialogCondition() { Left = "a", Op = "=", Right = "b" } } } } }; var expected = JsonConvert.SerializeObject(bundle, Formatting.None, new JsonSerializerSettings() { StringEscapeHandling = StringEscapeHandling.EscapeNonAscii }); //var expected = "[" + // "{" + // "\"title\":\"a nifty rule\"," + // "\"displayAs\":\"tunafish rep\"," + // "\"conditions\":[" + // "{" + // "\"op\":\"=!\"," + // "\"left\":\"yaday first\"," + // "\"right\":\"blahblah some more\"" + // "}," + // "{" + // "\"op\":\"=\"," + // "\"left\":\"another line of fun\"," + // "\"right\":\"twice the pain\"" + // "}" + // "]," + // "\"dialogs\":[" + // "{" + // "\"speaker\":\"player1\"," + // "\"line\":\"speaking line text\r\nmulti line\"" + // "}," + // "{" + // "\"speaker\":\"player2\"," + // "\"line\":\"something meaningful\"" + // "}" + // "]," + // "\"outcomes\":[" + // "{" + // "\"action\":\"doit\"" + // "}," + // "{" + // "\"action\":\"doit again\"" + // "}" + // "]" + // "}" + // "" + // "]"; // if thething is theotherthing: // muffin is true var program = new WordLangResults(src); Assert.AreEqual(false, program.ParserErrors.AnyErrors); var v = new ProgramToJson(); var output = v.Visit(program.ProgramContext); Assert.IsNotNull(output); var backwards = JsonConvert.DeserializeObject <DialogBundle>(output); Assert.AreEqual(backwards, bundle); Assert.AreEqual(expected, output); }
public void StringAndIntBags() { var player = new { health = 10, nums = new BagIntElement[] { new BagIntElement() { name = "a", value = 5 } }.ToList(), strs = new BagStringElement[] { new BagStringElement() { name = "a", value = "tuna" } }.ToList() }; var rules = new DialogRule[] { new DialogRule() { Name = "I have full health!", Conditions = new DialogRule.DialogCondition[] { new DialogRule.DialogCondition() { Left = "player.nums.a", Op = "=", Right = "5" }, new DialogRule.DialogCondition() { Left = "player.nums.b", Op = ">", Right = "6" }, new DialogRule.DialogCondition() { Left = "player.strs.a", Op = "=!", Right = "player.strs.b" } } }, }; var engine = new DialogEngine() .AddHandler(new BagIntHandler()) .AddHandler(new BagStringHandler()); var attributes = new DialogAttribute[] { new ObjectDialogAttribute(player, "player", "health"), DialogAttribute.New("player.nums", 10, player.nums).UpdateElements(engine), DialogAttribute.New("player.strs", "eggs", player.strs).UpdateElements(engine) //new BagDialogAttribute<bool>("player.flags", player.flags).UpdateElements(engine) }; attributes.ToList().ForEach(a => engine.AddAttribute(a)); rules.ToList().ForEach(r => engine.AddRule(r)); var best = engine.GetBestValidDialog(); Assert.IsNotNull(best); Assert.AreEqual("I have full health!", best.Name); }
public void SimpleEngineOutcomeRunner() { var player = new Actor(); player.MaxHealth = 100; player.Health = 100; var rules = new DialogRule[] { new DialogRule() { Name = "I have full health!", Conditions = new DialogRule.DialogCondition[] { new DialogRule.DialogCondition() { Left = "player.health", Op = "=", Right = "player.maxHealth" } }, Outcomes = new DialogRule.DialogOutcome[] { new DialogRule.DialogOutcome() { Command = "run", Target = "player.sampleFunc", Arguments = new Dictionary <string, string>() { { "h", "(/ player.maxHealth 2)" }, { "ammo", "55" } } } } } }; // new OFDA(player, "setAll", new Dictionary<string, string>(){ var attributes = new DialogAttribute[] { new ObjectDialogAttribute(player, "player", "health"), new ObjectDialogAttribute(player, "player", "maxHealth"), new ObjectDialogAttribute(player, "player", "ammo"), new ObjectFunctionDialogAttribute("player.sampleFunc", new Action <Dictionary <string, object> >(vars => { var health = (int)vars["h"]; var maxHealth = (int)vars["mx"]; var ammo = (int)vars["ammo"]; player.SetAll(health, maxHealth, ammo); }), new Dictionary <string, object> { { "mx", 200 } }) }; var engine = new DialogEngine(); rules.ToList().ForEach(r => engine.AddRule(r)); attributes.ToList().ForEach(a => engine.AddAttribute(a)); var best = engine.GetBestValidDialog(); Assert.IsNotNull(best); Assert.AreEqual("I have full health!", best.Name); engine.ExecuteRuleOutcomes(best); Assert.AreEqual(50, player.Health); Assert.AreEqual(200, player.MaxHealth); Assert.AreEqual(55, player.Ammo); }
public TutorialRule(DialogRule inRule, string inRuleGameArea) { this.rule = inRule; this.gameArea = inRuleGameArea; }