NPC asking the User for a password

Hello All,

Is it possible to have an NPC ask the user for a specific password prior to the start of conversation?

Would it be a conversation node? Or an NPC Object?

Any help would be beneficial.

3 Likes

Welcome to the TADS forum!

Depending upon the specifics of your situation, it seems like there could be many ways to achieve what you want. My game hasn’t been heavily conversation-based, so there are others that might be able to whip up sample code more quickly than I can.

If you want the NPC to start the conversation without the player having tried to talk first, you can use an AgendaItem, or the initiateConversation method triggered from some other code, perhaps a beforeAction.

Most likely in any case you will be entering a ConvNode, whether through NPC’s initiative or in response to some player-entered verb like TALK TO, ASK ABOUT, etc.

1 Like

I am very thankful for your reply!

I have tried to use a beforeAction, but I don’t seem to have it correct. Here is a copy of the code I have written:

Hooded_Figure : Person 'hooded figure' 'figure'
    @Hidden_Alley
    "the hooded figure is carrying a torch, but his dark cloak prevents you from seeing his face.
    He is speaking in low tones, but you aren't close enough to make out what he is saying. "
    properName = 'Sadesh'
    globalParamName = 'figure'
    isHim = true
    password = 'THESE HANDS OF MINE'
    passwordEntered = nil

    beforeAction(){
        if (self.isFirstTime());{
            self.doAsk();
        }
    }
            
            dobjFor(Ask){
        verify(){
            if(passwordEntered);{
                "Yes, you already know the password."
                ;}
        }
        action(){
            local pwd = ask('WHAT IS THE SOUND OF DEATH? ');
            if (pwd == password) {
                "Excellent.";
                passwordEntered = true;
            }
            else {finishGameMsg(ftDeath, [finishOptionUndo]);
            }
        }
    }
;

Unless there is a lot more pertinent code that you haven’t shown, there are several inconsistencies there.
-doAsk isn’t defined anywhere, or isFirstTime
-ask() isn’t defined
-(you don’t need to use self. in front of TADS object properties and methods…)
-There is no dobjFor(Ask), the verbs are AskAbout and AskFor
Furthermore, you probably don’t want to override dobjFor(AskAbout) on the Actor… you should use TopicEntry objects instead. Your verify and action don’t call inherited, so they are very likely to give empty responses or strange behavior except under the particular circumstances you are imagining.
If you really want the figure to ask you for the password as soon as you encounter the figure, beforeAction is probably also not what you want. You’d probably use a ConvAgendaItem.

It’s hard to straighten things out exactly without knowing exactly what you’re trying to achieve.

1 Like

John - In case nobody has told you today:

You are an absolute champion.

My intent is to have a specific NPC (who belongs to a nefarious group of ne’er-do-wells) ask the User for a password the very first time the User interacts with him.

I am obviously out of my depth, despite how simple this sounded in my head.

The idea is to have the User choose to talk to the NPC, and then have the NPC immediately ask for the password. If the User doesn’t type the exact password, then I will call up an finishGameMsg.

If it is easier to code, my backup plan is to have the NPC ask for the password when the User asks about a specific topic.

I suppose it is clear by this point just how new I am to TADS.

Thank you for your help.

3 Likes

It’s pretty hard to get too far in TADS without having a good handle on what the docs have to say! There’s a lot to learn, but it’s really powerful once you come to grips with it.

These are two different scenarios, and really want to be handled differently.

If you really want the NPC to interrupt the player to demand the password, then you could do that in a beforeAction(), and if you want the password prompt to be modal/forced (that is, the player can’t just ignore it and walk out of the room) then you can probably get what you want by just printing the prompt and then reading the player response via inputManager.getInputLine() or something like that.

f you don’t want to handle it that way, and want the password prompt to be presented the first time does something conversational with the NPC (asks/tells them about something, greets them, talks to them, and so on) the “hook” you’re looking for is handleConversation(), on either the actor object (if you’re not using states) or on the appropriate state (if you are).

Here’s a little demo that illustrates how to approach this, although all it does is print “What is the password?”, where you probably want to do a replaceAction, trigger a convnode, or something like that:

#charset "us-ascii"
#include <adv3.h>
#include <en_us.h>

modify Person
        passwordFlag = nil
;

startRoom: Room 'Void' "This is a featureless void. ";
+me: Person;
+pebble: Thing 'small round pebble' 'pebble' "A small, round pebble. ";
+alice: Person 'Alice' 'Alice'
        "She looks like the first person you'd turn to in a problem. "
        isProperName = true
        isHer = true

        passwordCheck() {
                if(gActor.passwordFlag == true)
                        return(nil);

                "<q>What is the password?</q> Alice demands. ";

                return(true);
        }
;
++InConversationState
        specialDesc = "Alice is here, talking with you. "
        stateDesc = "Alice is talking with you. "
;
+++AskTellTopic @pebble
        "<q>It's a pebble,</q> she says. "
;
+++ConversationReadyState
        isInitState = true
        specialDesc = "Alice is here, not talking with you. "
        stateDesc = "Alice is not talking with you. "
        handleConversation(actor, topic, convType) {
                if(alice.passwordCheck() == true)
                        return;
                inherited(actor, topic, convType);
        }
;
++++HelloTopic "<q>Hello,</q> she says. ";
++++ByeTopic
        "<q>Bye,</q> she says. "
;

versionInfo: GameID;
gameMain: GameMainDef initialPlayerChar = me;
2 Likes

Nailed it!

Using handleConversation() and nesting it into the ConversationReadyState triggers the NPC asking for the password as soon as the player speaks to him for the first time.

Now comes the other half of my problem: Is it possible to have the password be a specific string of characters? I have tried fiddling around with inputManager.getInputLine() but it seems like that isn’t what I want.

Reading through the “Getting Started in TADS 3” only gets me so far. Is there another resource that you can point me to? I’d rather learn than have to bother you kind folk every time I get stuck.

EDIT: If this second question should be a different post, let me know and I’ll mark the above response as the answer because, honestly, you crushed it.

2 Likes

Learning TADS 3 is the best start guide… you can find it on the tads.org site

1 Like

@Scoyy You will also find that the most common way of dealing with TADS conversation is through objects. Here are two other ways to accomplish the above, that may be patterns for other things you might try to do:

Actor ;
+ InConversationState ;
++ DefaultAnyTopic
    matchScore = 500
    isActive = !talkCount
    topicResponse {
        //ask for the password
    }
;

The above topic will supersede all other defined topics because of the matchScore, but it will cease being active after the first time you use it. (Of course, if you have a recurring password situation this isn’t exactly what you’d want.)
And since the figure doesn’t seem to be very conversational, it’s helpful to know that it’s not mandatory to use an InConversationState… those particularly model polite conversation. An Actor can converse normally without the special state, there are simply no automatic greetings, farewells, or extra descriptions that “they are in conversation with you”.
Like so…

Actor ;
+ DefaultAnyTopic ...

Here is another possibility, where HermitActorState already takes care of fielding all conversational attempts to one method. The thing about this is that you’ll want to set the figure to another state afterwards, or else the figure will ask for the password on every single conversation attempt.

Actor ;
+ HermitActorState
    noResponse {
        //ask for password and handle responses
        figure.setCurState(someOtherState);
    }
;

As for the password:
Are you using adv3 or adv3Lite?
Because for adv3 you need inputManager.getInputLine(nil,nil).
Also you should probably define your password as a lowercase string, and then do

local resp = inputManager.getInputLine(nil,nil).toLower();

to make sure they match.

1 Like

Lol, I look away for two days and miss ANOTHER chance to be helpful!

I just implemented an analagous sequence in the last month, but JZ beat me to the punch. Again! For me, the magic cocktail was using initiateConversation. Note most of this pretty straight out of the Learning TADS 3 document.

npc : Person 'rude no boundaries person' 'rude person'
    "Just a person.  A rude, no boundaries person.  "
    location = intimidatingChair
    posture = sitting
;
+ npcTalking : InConversationState
    attentionSpan = nil
;
++ npcWaitingToPounce : ConversationReadyState
    isInitState = true
    afterTravel(traveler, connector) {  //hits PC as soon as they arrive
        inherited(traveler, connector);
        if (traveler == gPlayerChar)
            npc.initiateConversation(nil, 'gimmeDatPwd');  
    }
;
++ ConvNode 'gimmeDatPwd'
    npcGreetingMsg =
        "Before you can say anything, the rude person belts out, \"Gimme dat password.\"  "
    npcContinueList : ShuffledEventList {
        [
            '\"I said \'Gimme dat password.\'\"  ',
            '\"What part of \'password\' don\'t you understand?\"  ',
            '\"This is you.  \'Buh buh buh not my password.\'  Yes.  Give it.\"  ',
            '\"Don\'t make me shake you.\"  ',
            '\"I can wait all day for that password.\"  ' 
        ]
    }
    isSticky = true  // won't leave convo
    canEndConversation(actor, reason) {   //Let PC leave, but not end convo with 'bye'
        switch(reason) {
            case endConvBye:
                "Rude person ignores your attempted goodbye.  ";
                return blockEndConv;
            default:
                return true;
        }
    }
;
++ DefaultAnyTopic, ShuffledEventList  // nothing but password will do
	[
		'Rude NPC ignores your attempt to change the subject.  ',
		'Rude NPC wants to hear only one thing from you.  ',
		'\"The next two things you say better be \'pass\' and \word\'.\"  ',
                '\"Bup-bup-bup.  Password.\"  ',
		'\"I can\'t hear you if you\'re not saying \'password\'.\"  '
	]
;

I don’t have an exact analog to wait for password, but the document goes into some depth on this in section 14.7 Conversation Nodes. It suggests something along the lines of:

++ SpecialTopic 'tell the password'
    ['tell', 'rude', 'npc', 'the', 'password', 'give', 'say' ]
    topicResponse() = {
        "\"Fine,\" you say.  \"The password is ...\"';
        //Handle password entry here
    }
;

To the password entry part, I do a lot of character entry bits, and code like this gives me what I want:

    do {
        strSel = inputManager.getKey(nil, nil).toUpper();
	intSel = toInteger(strSel);
	"<<((strSel == 'Q') || ((intSel > 0) && (intSel <= maxVal))) ? strSel : 'X\nThat\'s not it, reenter:  '>>";
   } while ((strSel != 'Q') && ((intSel == 0) || (intSel > maxVal)));

Spins until player inputs a number in range 0…maxVal or ‘Q’ Seems like a similar approach would work by matching the inputManager.getInputLine(nil,nil).toLower(); ?

4 Likes

Sorry JJ :grimacing: Hadn’t been hearing from you in awhile… your example is clearly more detailed!

2 Likes

Lol, you had no way of knowing the moons aligned and I actually had something to offer this time! :]

2 Likes