That leaves me with the other method. Here is the code I came up with:
verb "ask", "question", "consult"The downside of the above is that you have to predict proper error messages for every case (it's conceivable that there are times where "That doesn't make any sense." doesn't cut it). Just the same, I was pleased that this worked at all.
* (LivingAsk) "about" "his"/"her"/"its" anything DoAsk
routine LivingAsk(var)
{
if var is not living
{
"That doesn't make any sense."
return false
}
local i
for (i = 2;i < words ;i++ )
{
if word[i] = "about"
break
}
local a
select word[(i + 1)]
case "his" : a = "he"
case "her" : a = "she"
case "its" : a = "it"
if var.pronoun ~= a or not Contains(var,xobject)
{
"That doesn't make any sense."
return false
}
else
return true
}
Anyhow, drumroll, please...
The easiest, simplest way to support >ASK CHARACTER ABOUT HIS POSSESSION
Just add this line to your code:removal "his","her","its","your"("Your" because we also want to accept, CHARACTER, GIVE ME YOUR POSSESSION)
Just ignoring these words completely will largely support our cause, I figure. It is more likely that the player will only use these words in instances where they make sense, then they are likely to type, ASK YOUR CHARACTER HIS ABOUT HER ITS POSSESSION (which will still be processed, using the removal method).
So, yeah, that'll make your game sound smarter. Otherwise, you could always mix-and-match between these two methods to make your game seem as smart as possible (I'd probably always declare "your" as a removal, as code that only applies to order_response's seems like it'd be a pain in the ass), and there's plenty of room for improvement with the routine-grammar-token route (for instance, you could have it rely on an ownership system that is unaffected by actual possession).
Without having tried the code, I think that looks like an excellent solution!
ReplyDeleteThis is probably a crazy idea, and I'm sure I don't understand how all this works well enough to suggest something plausible, but here it goes...
Can LivingAsk, or another routine that calls LivingAsk after finishing, determine which of several objects with the same noun (the keyword that the player used for the question) the NPC should be talking about, based on the adjective preceding the noun in the question?
Say that in one game, the PC, Conan, and Hercules all have swords. The Parser should be able to differentiate between "ASK CONAN ABOUT HIS SWORD", "ASK CONAN ABOUT MY SWORD", AND "ASK CONAN ABOUT HERCULES'S SWORD."
The first two examples should be doable, and yeah, you should be able to match the noun used for the xobject against everything held by the implied parent, rewriting the xobject value if necessary.
DeleteThe last example ("ASK CONAN ABOUT HERCULES'S SWORD.") is kind of impossible, from a dynamic parser perspective, since the command has to be understood on a grammar token level just for it to get to PreParse. Assuming Hercule's sword doesn't change hands, you'd be best off giving the sword object a "hercule's" adjective. If the sword *will* change hands, you could write a routine for moving objects between characters that automatically adds "character_name's" to a certain slot in the character's adjective property array (you could have the same routine also add "his" or whatever applicable possessive to the same adjective property array at this time... although you'd probably have to play with parse_rank so when "his" is used, a character's object ranks higher than others).
If you'd like example code of any of these things, let me know.
I can imagine how this could be done by writing a routine that assigns adjectives to the objects that change hands, and leaving an empty slot in the objects' noun properties. No need for example code. I was just thinking that an ASK/TELL system like that would be strong; for all my games, I'll probably just stick to the simple TALK TO, because NPCs are hard enough to implement as it is. ;)
DeleteI think LivingAsk could be made to differentiate between "his"/"her" and "my", changing the xobject if necessary, as you say. That would accomplish everything I was thinking of. Maybe the code could fit in a case "my" under select word[(i + 1)].
If you don't mind my asking, what does this code block do:
{
if word[i] = "about"
break
}
Is this telling the routine to quit when it finds the word "about" in the command?
The code block, of course, requires an understanding of for loops. There's a page here: http://hugo.gerynarsabode.org/index.php?title=For , but it's probably described better in the Hugo Book itself.
DeleteAnyways, the loop starts on word[2], which is where our object wording starts (although I really should have started on word[3], now that I think about it). We can't know how many words the player is using to describe the object, so we keep checking words (adding one value at a time), until we get to "about".
Now that we know word[x] is "about", we know that worde [x+1] is "his","her", or "its" as only that grammar line calls LivingAsk.
My code already differentiates between "his" and "her". It does this by checking the character's pronoun property. "his" will only work with characters with "he" as pronoun #1, "her" will only work with characters with "she" as pronoun #1, and so on.
Anyway, here is a version with extra code to work with "my":
verb "ask", "question", "consult"
* (LivingAsk) "about" "his"/"her"/"its"/"my" anything DoAsk
routine LivingAsk(var)
{
if var is not living
{
"That doesn't make any sense."
return false
}
local i
for (i = 3;i < words ;i++ )
{
if word[i] = "about"
break
}
local a
select word[(i + 1)]
case "his" : a = "he"
case "her" : a = "she"
case "its" : a = "it"
if word[(i + 1) = "my" and Contains(player, xobject)
return true
elseif var.pronoun ~= a or not Contains(var,xobject)
{
"That doesn't make any sense."
return false
}
else
return true
}
I should also mention that if this code were more perfect, it'd check that the relevant object isn't a component of the applicable character (I, for one, usually code body parts as components). In that case, I'd probably borrow code from the CheckReach replacement, which also checks to see if the relevant object is a component-of-a-component:
Deletep = obj.part_of
while p
{
if Contains(parent(player), p)
return true
p = p.part_of
}
(Of course, that code wouldn't work with LivingAsk as is.)
Actually, I can't think of any way to approach my idea without having to do something complicated and arcane in PreParse.
ReplyDelete