MudBytes
» MUDBytes Community » Coding Discussions » Coding and Design » DSL's specifically for AI/obj...
Pages: << prev 1, 2 next >>
DSL's specifically for AI/object interaction scripting
Silenus
Conjurer




Group: Members
Posts: 248
Joined: Feb 26, 2008

Go to the bottom of the page Go to the top of the page
#1 Posted Oct 3, 2008, 2:24 pm

I come primarily from an LPC background where the in game language is rather general purpose. Unlike most Very High Level languages it supports type annotations though the rules for checking these are probably not always clear to newcomers and occasionally differed to runtime or simply ignored. The question I have is whether any one has developed good Turing complete languages for doing specifically mud interaction scripting- that is used specifically to specify AI actor's action and responses... event scripts where you have a scene which needs to be played out before the player with multiple participants and props etc and so on.

I noticed most mudlibs in LPC completely lack such a sublanguage- perhaps because of the power of LPC the smaller semantic gap and convenience is offset by the general complexity of implementing a sublanguage or library given LPC's design. But outside the LPC world I wonder if such things are reasonably common. Are they?

Thanks in advance,

Silenus.




David Haley
Wizard






Group: Members
Posts: 5,730
Joined: Jun 30, 2007

Go to the bottom of the page Go to the top of the page
#2 Posted Oct 3, 2008, 3:22 pm

What kind of thing are you talking about specifically? Do you have an example of what you would want to script with this?
.........................
-- d.c.h --
BabbleMUD Project (custom codebase)
Legends of the Darkstone (head coder)
http://david.the-haleys.org
.........................

Silenus
Conjurer




Group: Members
Posts: 248
Joined: Feb 26, 2008

Go to the bottom of the page Go to the top of the page
#3 Posted Oct 3, 2008, 8:02 pm

Consider for example an innkeeper which responds to player requests perhaps in a stateful manner depending on the time of day and his/her mood and which might perform a series of actions depending on the circumstances of a request made by a player. For example the player might say "xxx, I would like to buy a meal."- the innkeep would proceed would respond with a series of actions 1. acknowledge the players request and take the money. 2. head to the kitchen to speak to the chef. 3. make a request of the chef. 4. then return and inform the player if he hasn't left the room that the meal is being prepared. 5. If the player is not to be seen queue in his memory that the player perhaps needs to be informed. 6. Return to his previous position in case other players have additional requests. Obviously all this should be done with relevant time delays in between.

Another example might be an encounter or boss encounter scene which has a prologue prior to the encounter and an epilogue depending on the outcome of the encounter. Multiple actors maybe involved in dialogue and actions with appropriate time delays and depending on a players actions the "dialogue" may take different courses leading to different results. Again with appropriate time delays.


David Haley
Wizard






Group: Members
Posts: 5,730
Joined: Jun 30, 2007

Go to the bottom of the page Go to the top of the page
#4 Posted Oct 4, 2008, 10:12 am

Hmm ok. Why do you feel the need for a DSL, and not just whatever normal scripting language? (Luaish, Pythonish, Rubyish, etc.)
.........................
-- d.c.h --
BabbleMUD Project (custom codebase)
Legends of the Darkstone (head coder)
http://david.the-haleys.org
.........................

Silenus
Conjurer




Group: Members
Posts: 248
Joined: Feb 26, 2008

Go to the bottom of the page Go to the top of the page
#5 Posted Oct 4, 2008, 7:19 pm

Well my thoughts are that it would be easier to handle in a scripting system of some sort rather than in the general purpose language might have some savings. I am just wondering if a simpler interface (scripting language) can be provided for beginners i.e. in LPC the way to do something like this might be-

object innkeeper = find_object(xxx);
object sil = find_player("silenus");

init()
{
    if( some condition ) innkeeper->eventForce("say hi");

    // wait for player action.
}

buy_callback_function()
{
      if( some condition ) { innkeeper->processBuy(player, item); innkeeper->eventForce("Thank you $N here is your $O", player, item); }
      call_out("next_action_call_back",5);
}

This quickly can get quite messy because of the entry points into the system, the fact that it's state based plus the callback structure. I am wondering if there are simpler solutions rather than forcing ppl to write alot of this sort of code or if naturally this sort of thing would have to be done anyhow which means in general most coders wont do much AI scripting since it's far more complex than sticking a plain monster in a room.





exeter
Magician






Group: Members
Posts: 60
Joined: Feb 26, 2008

Go to the bottom of the page Go to the top of the page
#6 Posted Oct 4, 2008, 10:33 pm

The reason (IMO) that most LPC MUDs don't have any such language is that the mudlib itself acts as a domain-specific language for describing interactions among game objects.

David Haley
Wizard






Group: Members
Posts: 5,730
Joined: Jun 30, 2007

Go to the bottom of the page Go to the top of the page
#7 Posted Oct 5, 2008, 11:08 am

Silenus said:
the fact that it's state based

How could something like this not be state based?

You mentioned that you wanted the language to be "Turing complete" -- I'll assume that what you really mean is "sufficiently complex to do interesting things" (without getting into theory of computation etc.). With that in mind, isn't it almost necessary for the language to be non-trivial syntactically?

What I would suggest is coming up with a mock-up of sorts that demonstrates the simplicity of scripting the innkeeper exchange, while allowing you do to interesting things. And then compare with a "smart" implementation in LPC (or whatever), showing that you are doing things more simply than is possible in LPC. It's possible that the "DSL" could just be whatever language you're already using, but with lots of helper functions that make life easier for the writer: common patterns or constructs can be encapsulated into library functions or objects.


(EDIT: s/patters/patterns/, oops)
.........................
-- d.c.h --
BabbleMUD Project (custom codebase)
Legends of the Darkstone (head coder)
http://david.the-haleys.org
.........................

Last edited Oct 5, 2008, 12:27 pm by David Haley
Vassi
Conjurer






Group: Members
Posts: 182
Joined: Sep 24, 2008

Go to the bottom of the page Go to the top of the page
#8 Posted Oct 5, 2008, 12:23 pm

Silenus said:
Well my thoughts are that it would be easier to handle in a scripting system of some sort rather than in the general purpose language might have some savings. I am just wondering if a simpler interface (scripting language) can be provided for beginners


Savings for who? You can still provide a simple interface for beginners by exposing a specific, and coherent, object model to a "general purpose" language. For instance, I'm using IronPython (which is basically Python that talks .NET) which works fine on its own but is much more useful once I start exposing objects to it. One of the things every one of my exposed objects has is a small class I built in five minutes called ScriptTags to handle state. Basically you log a tag with a key (that will hopefully be script\quest specific via a naming scheme) you fill the tag with an int and\or a string, and you set an expiration time stamp. The timestamp is checked when you request it, if the tag you're requesting exists - but has expired - it is deleted and you are told it doesn't exist.

Anyway, building a meaningful and easy to learn object model to an existing language is easier than finding a whole new, tailored, language to do exactly what you want. At that point all your 'beginners' have to do is learn the syntax basics of the language you're using, as well as basic conditionals and looping, and they're good to go.

Edit: Woops, didn't mean to repeat what David said, so in short: I agree.
.........................
Vassi no Diem et Tharin
<ramble/>

Last edited Oct 5, 2008, 12:24 pm by Vassi
Silenus
Conjurer




Group: Members
Posts: 248
Joined: Feb 26, 2008

Go to the bottom of the page Go to the top of the page
#9 Posted Oct 5, 2008, 5:10 pm

Actually I am well aware of some of the issues involved- i.e. you trade away in most languages your existing syntax for a foreign syntax which requires an effort to learn. I actually have already done such an exercise but ran out of good ideas on how to structure such code which would provide real savings in terms of code complexity. I am also not above using language extensions via libraries to get the job done.

By state based I meant in contrast to most interactions with npc objects which are effectively stateless even if they have some sort of rudimentary "AI". I believe certain libraries in LPC have a not so Turing complete language for simplifying some aspects of mud scripting though not the aspect that I am particularly interested in- i.e. Lima contains a Lpscript which seems to be there for simplifying the configuration of mud objects.

The callback structure of LPC makes alot of this quite complex if done naively. If you wrap the code in a library which allows for function pointer hooks. How this too is still problematic due to implementation issues in the language if you use anonymous functions and retain textual locality the runtime errors coming out of the system do not report back properly.

The reason I asked the initial question was I was wondering if there are better approaches out there to this problem than my simple mock-ups and how any such language addresses certain issues with respect to rechecking conditions after possible changes of the state between time delays. My initial sketch of this both library wise and DSL wise was to use guard clauses + command scripts and embedded LPC statements. The issue for me in this in order to keep thing simple is how to and when to recheck modified guard clauses (modified by the command actions themselves) and propagate this modified guard check after a time-delay. The complexity of this becomes however a bit high implementationally. Since the system would have to be able to infer the outcomes of various commands passed in.

David Haley
Wizard






Group: Members
Posts: 5,730
Joined: Jun 30, 2007

Go to the bottom of the page Go to the top of the page
#10 Posted Oct 6, 2008, 9:54 am

Why can't you have the relevant scripts be listeners on the data in question, and whenever it changes it fires a change event? They could then reevaluate the clauses in question, and take whatever action is necessary based on the condition changes, if any.
.........................
-- d.c.h --
BabbleMUD Project (custom codebase)
Legends of the Darkstone (head coder)
http://david.the-haleys.org
.........................

Silenus
Conjurer




Group: Members
Posts: 248
Joined: Feb 26, 2008

Go to the bottom of the page Go to the top of the page
#11 Posted Oct 6, 2008, 1:15 pm

There are benefits to using an event driven type approach but in this case the script itself may mutate the data causing the guard to become invalid on a subsequent rentry into the script. You could argue that this means that the script should be separated out into a separate listener however this (including the FSA like guard clauses) breaks up the narative structure alot making it hard to follow the flow at a glance.

I am envisioning these scripts as just being a series of commands issued by the actor in question and wondering if the guards can be updated in some manner as the actions occur since you should know in some sense what their pre-conditions and post-conditions are. Nested guards is another possibility- I guess this is an issue similar to type inference though perhaps a bit more complex. I.e. it may be possible in theory to infer in many cases what the condition should be after some action in the script occurs and modify the guard so that upon rentry the new condition conforms to the current state of affairs.

David Haley
Wizard






Group: Members
Posts: 5,730
Joined: Jun 30, 2007

Go to the bottom of the page Go to the top of the page
#12 Posted Oct 6, 2008, 1:34 pm

I have to admit that I'm a little confused here. You want the language to be sufficiently complex, yet you talk about it as only a sequence of actor commands in a narration. It would really help me to see an example of how you would script the innkeeper exchange so that I can reconcile the desired complexity with the simplicity.
.........................
-- d.c.h --
BabbleMUD Project (custom codebase)
Legends of the Darkstone (head coder)
http://david.the-haleys.org
.........................

Silenus
Conjurer




Group: Members
Posts: 248
Joined: Feb 26, 2008

Go to the bottom of the page Go to the top of the page
#13 Posted Oct 6, 2008, 11:16 pm

Well I was initially thinking of a language or interface that looked something like this (Ignore the absence of arguments passed in during event triggers)

block :- guard-clause statement*

guard-clause :- event* conditional-expression

statement :- command delay? | lambda-closure delay? | conditional-expression statement*

command :- actor-name? string // the actual command string

So perhaps

[encounter-player, ((not in-combat? innkeeper)) ]
"Greetings $N! Welcome to our humble inn."
"Can I be of some service?"

[buy-request, ((not-in-combat? innkeeper)) ]
  [(not (in-stock? $O))] "I apologize but we have run out of $O!"
  ["int-stock? $O]
  (
      "Please wait a moment let me contact the chef"
      "!Go north" 1
      "!Ask George to prepare $O" //assumes George is always present for simplicity
      "!Go south" 1
      "Thanks for waiting $N. George tells me that the food will be ready in 10 minutes." // A server or waiter will subsequently deliver the food
  )   

With the escape hatch via lambda closures I think that "the language" is reasonably powerful. The problem is to what extent you can remove some of the explicit condition guards in an environment where the players can perform actions during time delays which can invalidate some of your conditions. What happens for example if the innkeeper gets attacked on the way to the kitchen? Obviously you can make these explicit- but ideally like with type-inference based on some post-condition/pre-condition/invariant logic for commands and re-evaluation of enclosing guards etc might make it possible to remove some of the uglier guards?   


David Haley
Wizard






Group: Members
Posts: 5,730
Joined: Jun 30, 2007

Go to the bottom of the page Go to the top of the page
#14 Posted Oct 7, 2008, 10:06 am

You could treat it as a sequence of tasks as opposed to actual commands. The task of asking for the food to be prepared is conditioned on the innkeeper not being in combat. The task is broken into three sub-tasks: (1) going to the room, (2) making the request, (3) returning to the storefront. Task 2 depends on task 1 being complete. Tasks (1) and (3) are dynamically broken into sub-tasks depending on where the innkeeper is located. If a task is interrupted, you know where you are in the list of accomplished goals.

In other words, don't script a list of actions, script a list of goals with preconditions. Then have a planner engine to work out the details for you based on current conditions. I'm not sure how to best represent this syntactically but I imagine it wouldn't be too bad.
.........................
-- d.c.h --
BabbleMUD Project (custom codebase)
Legends of the Darkstone (head coder)
http://david.the-haleys.org
.........................

effigies
Fledgling




Group: Members
Posts: 5
Joined: Mar 14, 2008

Go to the bottom of the page Go to the top of the page
#15 Posted Oct 7, 2008, 12:45 pm

I think you need to recheck your LPC foo.  1) Lima is old, unsupported, and was really weird when it was supported.  2) scripting NPCs to do different things based on conditions that are represented in game is really trivial in LP.  I have most experience with the Nightmare/Foundation/Dead Souls (which is actively maintained and has an active developer community) family, and I know you can build this kind of functionality into a single NPC or into an inheritable so you repeat work as little as possible.  3) Designing an intelligent inheritable is a bit more work in the short run, but easily doable and if you need even more power, you can build some kind of Innkeeper AI daemon that will handle this globally. 4) adding another layer of complexity seems like a bad fit for this to me.  If that is what you want to do, then by all means go ahead, but do note that the tools provided can solve this problem even if you don't get how at this point.

Pages:<< prev 1, 2 next >>

Valid XHTML 1.1! Valid CSS!