1
\$\begingroup\$

I have a simple XML structure for my dialog between the player and NPCs. What I'd like to do is put variable changes (and maybe other things) directly into the XML. So, for instance, if you select a certain conversation option the character gives you gold. Like this:

<story>
  <segment id ="1">
    <dialog>
      <speaker>Fred</speaker>
      <text>Do you like futurecrew?</text>
    </dialog>
    <choice>
      <prompt>Yes</prompt>     
      <target>2</target>
      <command>$gold-10</command>
    </choice>
    <choice>
      <prompt>No</prompt>
      <target>3</target>
      <command>$relationship-20</command>      
    </choice>    
  </segment>
</story>

In exploring this issue I have written a really terrible brute force command parser, but it just feels wrong at so many levels:

public class Command
    {
        string commandText;
        Symbol symbol;
        Field field;

        public Command(string _commandText)
        {
            commandText = _commandText;
        }

        public void Execute()
        {           

            //look for operators
            int test = -1;
            int location = -1;
            int amount = 0;

            test = commandText.IndexOf("-");
            if (test != -1)
            {
                symbol = Symbol.Minus;
                location = test;
            }
            test = commandText.IndexOf("+");
            if (test != -1)
            {
                symbol = Symbol.Plus;
                location = test;
            }
            test = commandText.IndexOf("*");
            if (test != -1)
            {
                symbol = Symbol.Multiply;
                location = test;
            }
            test = commandText.IndexOf("/");
            if (test != -1)
            {
                symbol = Symbol.Divide;
                location = test;
            }
            string variable = commandText.Substring(0, location);
            amount = Int32.Parse(commandText.Substring(location + 1));

            if (variable.ToUpper() == "$GOLD")
                field = Field.Gold;

            if (field == Field.Gold)
            {
                Logger.log("Gold before {0}", Game.Instance.Gold);

                if (symbol == Symbol.Minus)
                    Game.Instance.Gold -= amount;
                if (symbol == Symbol.Plus)
                    Game.Instance.Gold += amount;

                Logger.log("Gold after {0}", Game.Instance.Gold);
            }
        }
    }

If I have 30 different variables I want to "expose" to the XML "scripting" it looks like I'll be writing a lot of stupid achey breaky code.

I have searched around and found people asking/answering about conditions, which I see as simpler than this. I have also seen suggestions for CodeDom for realtime compiling but this is in unity C# so I don't anticipate that will work. I looked into LUA for .NET and IronPython but that seems overkill when really I just want the ability to change variables on my Game singleton.

Any ideas or direction would be much appreciated!

EDIT: I found UniLua https://github.com/xebecnan/UniLua for a unity safe pure c# implementation of lua. I haven't decided yet if I'll use it, but my presupposition that I couldn't use Lua turned out to be false.

\$\endgroup\$
3
\$\begingroup\$

Using an existing scripting language like Lua may be overkill for your needs, but on the other hand it also actually solves your needs with a minimal amount of effort wasted reimplementing the wheel. I would reconsider its use. Especially as a scripting language of this type can come handy in plenty of other places.

If you really just don't want to use Lua, another option is to build a generic IDialogCommand sort of thing that can be bound to a dialog file. A dialog option can include one or more commands, which are just classes that derive from IDialogCommand. They can include parameters marked up in the XML which are loaded into the command class instances via serialization of some form. An example XML bit might look like:

<dialog>
  <speaker>Palpatine</speaker>
  <text>Something something dark side.</text>
  <command type="GiveGold">
    <amount>30</amount>
  </command>
  <command type="GrantXP">
    <amount>1000</amount>
  </command>
  <command type="Effect">
    <duration>60</duration> <!-- in seconds -->
    <effect type="Stat">
      <stat>Strength</stat>
      <amount>5</amount>
    </effect>
  </command>        
</dialog>

Using a registration manager or even just C# reflection, you can create a list of factories to use for the <command> elements. For instance, you might have

class GiveGoldCommand : IDialogCommand
{
  public int Amount { get; set; }

  IDialogCommand.Apply(Character player)
  {
    player.Gold += Amount;
  }
}

// elsewhere
DialogCommandRegister.Register("GiveGold", new CommandFactory<GiveGoldCommand>());

Note that such a system is essentially not actually better than using a simple sandboxed scripting language in most respects unless you also build a good dialog editor that naturally understands the commands and uses them to create appropriate UI for each command.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.