Skip to content

Instantly share code, notes, and snippets.

@Bocom
Created June 14, 2013 01:09
Show Gist options
  • Save Bocom/5778721 to your computer and use it in GitHub Desktop.
Save Bocom/5778721 to your computer and use it in GitHub Desktop.
Horrible code made through throwing stuff at the wall
using System;
using System.Collections.Generic;
using System.IO;
namespace NewSceneManager.Dialogue
{
public class DialogueEngine
{
Dictionary<string, DialogueBlock> labels;
List<DialogueCharacter> characters;
public DialogueEngine()
{
labels = new Dictionary<string, DialogueBlock>();
characters = new List<DialogueCharacter>();
}
void ParseLabel(string labelName, List<string> labelNode)
{
labels.Add(labelName, DialogueBlock.ParseLabel(this, labelNode));
}
public void ParseScript(string filename)
{
var rawFile = File.OpenText(Path.GetFullPath(filename));
bool readingLabel = false;
Dictionary<string, List<string>> rawLabels = new Dictionary<string, List<string>>();
List<string> labelLines = new List<string>();
string labelName = "";
while (!rawFile.EndOfStream)
{
string line = rawFile.ReadLine();
if (readingLabel)
{
labelLines.Add(line.Trim());
if (line == "}")
{
readingLabel = false;
rawLabels.Add(Path.GetFileNameWithoutExtension(filename)+"."+labelName, labelLines);
labelName = "";
labelLines = new List<string>();
}
}
else
{
string[] parts = line.Split(' ');
if (parts[0] == "label")
{
labelLines.Add(line.Trim());
labelName = parts[1];
readingLabel = true;
}
}
}
foreach (var label in rawLabels)
{
ParseLabel(label.Key, label.Value);
}
}
internal void Run()
{
foreach (var label in labels)
{
Console.WriteLine("Running label \"" + label.Key + "\"");
label.Value.RunBlock();
Console.WriteLine();
}
}
}
class DialogueCharacter
{
}
struct DialogueChoiceEntry
{
public string Text;
public DialogueBlock Block;
public DialogueChoiceEntry(string text, DialogueBlock block)
{
Text = text;
Block = block;
}
}
class DialogueChoiceBlock
{
public List<DialogueChoiceEntry> Choices;
public DialogueChoiceBlock()
{
Choices = new List<DialogueChoiceEntry>();
}
public static DialogueChoiceBlock Parse(DialogueEngine de, List<string> lines)
{
DialogueChoiceBlock dcb = new DialogueChoiceBlock();
char[] splitSpc = new char[] { ' ' };
List<string> blockLines = new List<string>();
bool inBlock = false;
string text = "";
foreach (var line in lines)
{
string[] op = line.Split(splitSpc, 2);
if (inBlock)
{
if (line.Contains("}"))
{
inBlock = false;
var db = new DialogueBlock(de);
db.Parse(blockLines.ToArray());
dcb.Choices.Add(new DialogueChoiceEntry(text, db));
text = "";
blockLines = new List<string>();
}
else
blockLines.Add(line);
}
if (op[0] == "choice")
{
int len = op[1].Length;
int lidx = op[1].LastIndexOf(" ");
text = op[1].Substring(0, lidx);
inBlock = true;
}
}
return dcb;
}
}
class DialogueBlock
{
List<Operation> ops;
List<DialogueChoiceBlock> choiceBlocks;
int pc;
DialogueEngine de;
Operation Op { get { return ops[pc]; } }
public int Length { get { return ops.Count; } }
public DialogueBlock(DialogueEngine de)
{
this.de = de;
ops = new List<Operation>();
choiceBlocks = new List<DialogueChoiceBlock>();
pc = 0;
}
public void RunBlock()
{
while (pc < ops.Count)
{
ops[pc].Code();
pc++;
}
}
public void OpSay()
{
Console.WriteLine((Op.Args[0] == null ? "Narrator" : Op.Args[0]) + " says {0}", Op.Args[1]);
}
public void OpShowPortrait()
{
Console.WriteLine("Showing {1} {0}", Op.Args[0], Op.Args[1]);
}
public void OpHidePortrait()
{
Console.WriteLine("Hiding {0}", Op.Args[0]);
}
public void OpClearPortraits()
{
Console.WriteLine("Clearing portraits");
}
public void OpGotoLabel()
{
Console.WriteLine("Going to label {0}", Op.Args[0]);
}
public void OpRunChoiceBlock()
{
var dcb = choiceBlocks[(int)Op.Args[0]];
Console.WriteLine("Choice block:");
dcb.Choices.ForEach((x) => { Console.WriteLine("\t" + x.Text); x.Block.RunBlock(); });
}
public void OpSelection()
{
Console.WriteLine("Came upon a selection");
Conditional cond = (Conditional)Op.Args[0];
bool hasElse = (bool)Op.Args[2];
bool res = cond.Run();
if (res)
{
Console.WriteLine("The selection returned true!");
((DialogueBlock)Op.Args[1]).RunBlock();
if (hasElse)
pc++;
}
else
{
Console.WriteLine("The selection returned false!");
}
}
public void OpRunBlock()
{
Console.WriteLine("Running a block");
((DialogueBlock)Op.Args[0]).RunBlock();
}
public static DialogueBlock Parse(DialogueEngine de, string[] blockLines)
{
DialogueBlock ret = new DialogueBlock(de);
ret.Parse(blockLines);
return ret;
}
public void Parse(string[] blockLines)
{
int parentBlockDepth = 0;
int blockDepth = 0;
bool parsingChoiceBlock = false;
bool parsingSelectionBlock = false;
bool readingIf = false;
bool readingElse = false;
bool hasElse = false;
List<string> choiceLines = new List<string>();
List<string> selectionLines = new List<string>();
string condLine = "";
char[] splitSpc = new char[] { ' ' };
int choiceIndex = 0;
//Console.WriteLine(labelNode[0]);
//foreach (var node in blockLines)
for (int i = 0; i < blockLines.Length; i++)
{
string node = blockLines[i];
if (node.Contains("}"))
blockDepth--;
if (node.Contains("{"))
blockDepth++;
if (parsingSelectionBlock)
{
if (blockDepth > parentBlockDepth)
selectionLines.Add(node);
else if (blockDepth <= parentBlockDepth)
{
parentBlockDepth = 0;
var dcb = DialogueBlock.Parse(de, selectionLines.ToArray());
selectionLines.Clear();
if (readingIf)
{
//parsingSelectionBlock = false;
readingIf = false;
var next = blockLines[i + 1].Split(' ')[0];
if (next == "else")
{
hasElse = true;
}
Conditional cond = Conditional.Build(condLine);
ops.Add(new Operation(OpSelection, cond, dcb, hasElse));
}
else if (readingElse)
{
readingElse = false;
ops.Add(new Operation(OpRunBlock, dcb));
}
parsingSelectionBlock = false;
}
continue;
}
if (parsingChoiceBlock)
{
if (blockDepth > parentBlockDepth)
{
choiceLines.Add(node);
}
else if (blockDepth <= parentBlockDepth)
{
parsingChoiceBlock = false;
parentBlockDepth = 0;
var dcb = DialogueChoiceBlock.Parse(de, choiceLines);
choiceBlocks.Add(dcb);
ops.Add(new Operation(OpRunChoiceBlock, choiceIndex));
choiceLines.Clear();
choiceIndex++;
}
continue;
}
string[] op = node.Split(splitSpc, 2);
if (op[0] == "say")
{
// Shows a line of dialogue as either character dialogue or narration
if (op[1][0] != '"')
{
// Character defined
string[] args = op[1].Split(splitSpc, 2);
ops.Add(new Operation(OpSay, args));
}
else
{
// Narration
ops.Add(new Operation(OpSay, null, op[1]));
}
}
else if (op[0] == "show")
{
// Show a character portrait.
// Replace a character's portrait.
string[] args = op[1].Split(splitSpc);
// Here we need a check to see if a character is already shown.
if (args.Length > 1)
{
// State included
ops.Add(new Operation(OpShowPortrait, args));
}
else
{
// Show default
ops.Add(new Operation(OpShowPortrait, args[0], "Default"));
}
}
else if (op[0] == "hide")
{
// Hide op[1]
ops.Add(new Operation(OpHidePortrait, op[1]));
}
else if (op[0] == "goto")
{
// Go to another label
// TODO: Specialize this probably
ops.Add(new Operation(OpGotoLabel, op[1]));
}
else if (op[0] == "clear")
{
// Clear existing portraits
ops.Add(new Operation(OpClearPortraits));
}
else if (op[0] == "execute")
{
// Execute a script file
Console.WriteLine("execute is not handled.");
}
else if (op[0] == "choices")
{
// Defines a choices block
parentBlockDepth = blockDepth - 1;
parsingChoiceBlock = true;
}
else if (op[0] == "sets")
{
// Change a switch's value
Console.WriteLine("sets is not handled.");
}
else if (op[0] == "setv")
{
// Change a variable's value
Console.WriteLine("setv is not handled.");
}
else if (op[0] == "if" || op[0] == "elif")
{
// Selection
parentBlockDepth = blockDepth - 1;
var si = node.IndexOf("(") + 1;
var ei = node.LastIndexOf(")") - si;
condLine = node.Substring(si, ei);
parsingSelectionBlock = true;
readingIf = true;
}
//else if (op[0] == "elif")
//{
// // Extra selection
// Console.WriteLine("elif is not handled.");
// // Oh shit!
//}
else if (op[0] == "else")
{
// Even more selection
parentBlockDepth = blockDepth - 1;
parsingSelectionBlock = true;
readingElse = true;
}
}
//Console.WriteLine(labelNode[labelNode.Count - 1]);
if (blockDepth != 0)
throw new Exception("blockDepth");
}
public static DialogueBlock ParseLabel(DialogueEngine de, List<string> labelLines)
{
DialogueBlock dl = new DialogueBlock(de);
string[] labelContents = labelLines.GetRange(1, labelLines.Count - 2).ToArray();
dl.Parse(labelContents);
return dl;
}
}
class CondFuncs
{
public static bool Equals(object[] args)
{
return args[0].Equals(args[1]);
}
public static bool NotEquals(object[] args)
{
return !args[0].Equals(args[1]);
}
public static bool Greater(object[] args)
{
return (int)args[0] > (int)args[1];
}
public static bool GreaterEquals(object[] args)
{
return (int)args[0] >= (int)args[1];
}
public static bool Lesser(object[] args)
{
return (int)args[0] < (int)args[1];
}
public static bool LesserEquals(object[] args)
{
return (int)args[0] <= (int)args[1];
}
public static bool And(object[] args)
{
return And((Conditional)args[0], (Conditional)args[1]);
}
public static bool And(Conditional arg1, Conditional arg2)
{
var a1 = arg1.Run();
if (!a1)
return false;
return a1 && arg2.Run();
}
public static bool Or(object[] args)
{
return Or((Conditional)args[0], (Conditional)args[1]);
}
public static bool Or(Conditional arg1, Conditional arg2)
{
return arg1.Run() || arg2.Run();
}
public static bool HasItem(object[] args)
{
return HasItem(args[0]);
}
// TODO: Make HasItem return actual value.
public static bool HasItem(object arg)
{
return true;
}
public static bool GetSwitch(object[] args)
{
return GetSwitch(args[0]);
}
// TODO: Make GetSwitch return actual value.
public static bool GetSwitch(object arg)
{
return false;
}
public static object GetVar(object[] args)
{
return GetVar(args[0]);
}
// TODO: Make GetVar return actual value.
public static object GetVar(object arg)
{
return 1;
}
}
struct Conditional
{
public Func<object[], bool> Func;
public object[] Args;
public Conditional(Func<object[], bool> func, params object[] args)
{
Func = func;
Args = args;
}
public void SetArguments(params object[] args)
{
Args = args;
}
public static Conditional Build(string inp)
{
// TODO: Temporary
Conditional cond = new Conditional();
Conditional nested = new Conditional();
if (inp.Contains("("))
{
var si = inp.IndexOf("(") + 1;
var ei = inp.LastIndexOf(")") - si;
var condLine = inp.Substring(si, ei);
// FIXME: needs a check for parenthesis that are on the left side too.
inp = inp.Substring(0, si - 1) + "(nested)";
nested = Conditional.Build(condLine);
}
List<Conditional> conds = new List<Conditional>();
var aksjd = inp.Split(' ');
bool andor1 = false;
bool andor2 = false;
Conditional andorCond = new Conditional();
for (int i = 0; i < aksjd.Length; i++)
{
var item = aksjd[i];
var c = new Conditional();
if (andor1)
andor2 = true;
if (item == "has_item")
{
c.Func = CondFuncs.HasItem;
var itemName = aksjd[++i];
c.SetArguments(itemName);
}
else if (item == "switch")
{
c.Func = CondFuncs.GetSwitch;
var switchName = aksjd[++i];
c.SetArguments(switchName);
}
else if (item == "var")
{
var varName = aksjd[++i];
var op = aksjd[++i];
var val = aksjd[++i];
switch (op)
{
case ">":
c.Func = CondFuncs.Greater;
break;
case "<":
c.Func = CondFuncs.Lesser;
break;
case ">=":
c.Func = CondFuncs.GreaterEquals;
break;
case "<=":
c.Func = CondFuncs.LesserEquals;
break;
default:
case "==":
c.Func = CondFuncs.Equals;
break;
case "!=":
c.Func = CondFuncs.NotEquals;
break;
}
// TODO: THIS IS WRONG
c.SetArguments(
(int)CondFuncs.GetVar(varName),
int.Parse(val));
}
else if (item == "and")
{
c.Func = CondFuncs.And;
var c1 = conds[conds.Count - 1];
conds.RemoveAt(conds.Count - 1);
c.SetArguments(c1, null);
andorCond = c;
andor1 = true;
}
else if (item == "or")
{
c.Func = CondFuncs.Or;
var c1 = conds[conds.Count - 1];
conds.RemoveAt(conds.Count - 1);
c.SetArguments(c1, null);
andorCond = c;
andor1 = true;
}
else if (item == "(nested)")
{
c = nested;
}
if (andor2)
{
andor2 = false;
andorCond.Args[1] = c;
conds.Add(andorCond);
andorCond = new Conditional();
}
else if (!andor1)
{
conds.Add(c);
}
}
cond = conds[0];
return cond;
}
public bool Run()
{
return Func(Args);
}
}
struct Operation
{
public Action Code;
public object[] Args;
public Operation(Action code, params object[] args)
{
Code = code;
Args = args;
}
public override string ToString()
{
return "Op("+Code.ToString()+", "+Args.ToString()+")";
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment