TADS 3 YesTopic with multiple NPCs present

Hello all.

First post, so please be gentle with me if I accidentally transgress any board rules.

I’m trying to program a conversation between the PC and Alice in which a third NPC, Bob, is also present but takes no part in the conversation. (He’s doing his own thing elsewhere in the room).

At several key moments, Alice asks the PC a question which responds to YesTopic and NoTopic.

However, in testing, when the PC types YES or NO, the game responds “You must be more specific about whom you want to talk to.”

This happens regardless of whether Bob is in a Hermit or ConversationReady state.

If I temporarily remove Bob from the room until the question is answered, the game correctly processes YES and NO responses.

But this solution is inelegant and prevents the PC choosing to interact with Bob instead of answering Alice’s question.

Is there a way to make the YES and NO responses seamless?

Do you have the YesTopic and NoTopic located in ConvNode?

Yup.

As I say, the conversation works perfectly if I remove Bob from the room.

And is the ConvNode active? And isn’t the ConvNode being deactivated for some reason? ConvNode is normally active only for one turn, if not followed, then it is automatically leaved unless you mark the ConvNode with isSticky = true. Strange, I have two NPCs in my game in the same room, one is in conversation with the player, asks questions and I didn’t have any problem like that regardless whatever my secondary actor is in ActorState or HermitActorState. Could you extract minimal but fully working sample source code demonstrating the problem and commands you type?

I’ve solved the problem, thanks for the pointer tomasb.

It looks like the problem was coming from the fact that I had Alice coming into the room for the first time already in her InConversationState and immediately asking a question. Something like this:

alice.moveIntoForTravel(firstRoom); "<q>Yes or no?</q>, says Alice."; alice.setConvNode('question');

I guess TADS didn’t recognize that a conversation had started.

Replacing with the following code seems to do the trick.

alice.moveIntoForTravel(firstRoom); "<q>Yes or no?</q>, says Alice."; alice.initiateConversation(aliceTalking, 'question');

Thanks for the responses.

Yes, initiateConversation(state, node) is correct way to initiate conversation programatically such as NPC asking a question, setConvNode(node) method is for setting/changing node in already running conversation only. Maybe one little tweak to be more stylish is to assign double quoted string with question to npcGreetingMsg property of the ConvNode instead of printing it directly.

Good advice, thanks.

I still can’t figure out why TADS understood a conversation to have started when there was only one NPC in the room in my original code that didn’t use initiateConversation.

It’s moot, anyway, as my problem is now solved.

If there’s only one NPC in scope, conversational commands get automatically directed to that NPC, since there’s no need for disambiguation prompts.

Indeed. But if there’s two NPCs in the room, you have to initiateConversation, which is not true if there’s only one NPC there.

If there’s only one NPC in the room, it suffices to simply have them walk in primed in their InConversationState then setConvNode and it works exactly the same.

That works, for some reason I don’t understand.

You should initiateConversation() any time the NPC starts talking to the player (as opposite when player start talking to NPC) even with one NPC, the effect of seemingly working is more of a coincidence, you fool TADS into thinking that player is just starting conversation to NPC on his own will.

If you look to the initiateConversation method, you will see that you skipped over ActorHello functionality (instead of normal Hello) and setting node reason. You won’t probably note that in practice, but more importantly you’ve skipped over the noteConversation(gPlayerChar); which is responsible for notifying TADS about established conversation with one of the NPCs, which is the reason for the weird behaviour you describe.

[code] initiateConversation(state, node)
{
/*
* if there’s no state provided, use the current state’s implied
* conversation state
*/
if (state == nil)
state = curState.getImpliedConvState;

    /* 
     *   if there's an ActorHelloTopic for the old state, invoke it to
     *   show the greeting 
     */
    curState.handleTopic(self, actorHelloTopicObj, helloConvType, nil);

    /* switch to the new state, if it's not the current state */
    if (state != nil && state != curState)
        setCurState(state);

    /* we're now talking to the player character */
    noteConversation(gPlayerChar);

    /* switch to the conversation node */
    setConvNodeReason(node, 'initiateConversation');

    /* tell the conversation node that the NPC is initiating it */
    if (node != nil)
        curConvNode.npcInitiateConversation();
}[/code]