Saturday, July 05, 2014

NPC Scripting

I've been working less on the game than I would like lately - well, I should say that I've been coding on the game less than I'd like.  The work amount has remained the same, if not actually increased since the last post.

NPC scripting has been my primary focus, as it has a lot of definition for the rest of the project.  It took me a long while to decide on a structure for the NPC scripting (and actions scripting in general in the game for other things, like doors, chests, etc - they all follow this structure under the hood), but I finally went with XML as a formal language for it.  I was juggling around the idea of JSON, and my own weird markup, but then I was finding myself trying to work around nesting things, duplicate things, which XML already handles without getting really ugly and hard to follow syntactically.

So here's an example K-Mart greeter NPC script, I hope it speaks for itself and shows some of the structure I've put into the game.

<npc display_name="Bob Johnson" id_name="bobJohnson">
    <action_set order="1" flag_required="-insulted_greeter, -impressed_greeter">
        <action order="1" type="talk" text="Welcome to K-Mart!"/>
        <action order="2" type="choice" text="Can I help you with anything?">
            <choice order="1" text="Go away!">
                <action order="1" type="talk" text="Well!"/>
                <action order="2" type="give_flag" flag="insulted_greeter"/>
                <action order="3" type="set_animation" animation="upset" target="bobJohnson"/>
            </choice>
            <choice order="2" text="Howdy!  You're an awesome greeter!">
                <action order="1" type="talk" text="You're an awesome customer!"/>
                <action order="2" type="give_flag" flag="impressed_greeter"/>
                <action order="3" type="set_animation" animation="dance" target="bobJohnson"/>
            </choice>
        </action>
    </action_set>
    <action_set order="2" flag_required="insulted_greeter" item_required="" equipped_required="">
        <action order="1" type="talk" text="I hope you have a nice dea- I mean day!"/>
    </action_set>
    <action_set order="3" flag_required="impressed_greeter">
        <action order="1" type="talk" text="You complete me!"/>
    </action_set>
</npc>

So the game will check to see if the NPC bobJohnson should even be loaded before all of this (maybe he won't show up until the last greeter got fired by one of your devious quests) but it also has requirement checks available for each set of actions as well.  Sometimes you might want an NPC to only say something to you about a quest if you're a particular character, or have a particular item, or have already talked to this other NPC about this other thing, or have this item equipped...etc.  So the action_sets are where the NPC parsing checks to see if they should do the nested actions in that action_set or not, or move on.  

I also put in an order field, not only for actions nested in the action_sets, but for the action_sets as well.  There are probably times that we're going to want one or more sets of actions to happen, and probably in a chronological sequence as well.  If the required flags weren't set for any of the action_sets in the example above, then the NPC would do all three of them:

NPC: Welcome to K-Mart!
NPC: Can I help you with anything?
1: Go away!
2: Howdy!  You're an awesome greeter!
(player would pick a choice, and the NPC would do the subsequent actions of course)
NPC: I hope you have a nice dea- I mean day!
NPC: You complete me!

And without any requirement checks in place, the same things would happen every time.  So, the person making the content would have to be diligent in their playtesting for each scenario they put in place.

Any thoughts?  I'm making a Kivy app right now to generate this xml from a nice interface/editor for the person that would make the content, and they'll copy paste that xml string into the script property of the npc from the Tiled editor.

No comments:

Post a Comment