Working example of Adv3Lite DefaultAgendaTopic?

Howdy everyone.

I was combing the internet for a working example of DefaultAgendaTopic and didn’t find one. This doesn’t seem to work (whether I put the bobLighthouseAgenda on bob or on the DefaultAgendaTopic).

Thank you!

+bob: Actor 'bob'
 "It's bob"
;

++ DefaultAgendaTopic
 "Bob default agenda topic response"
;

+++bobLighthouseAgenda: ConvAgendaItem
 isReady = true
 initiallyActive = true
 invokeItem()
 {
        switch(reasonInvoked) {
        case 1: 
            "Initiating conversation";
            break;
        case 2:
            "Lull in conversation";
            break;
        case 3:
            "DefaultAgendaTopic response";
            break;
        }
 }
 ;
2 Likes

Is AgendaTopic a thing in Lite? I haven’t heard of it…

2 Likes

So I was reading from this source, because while I use Adv3Lite a lot, I don’t do a lot with NPCs.

Based on what I’ve read, though, I think the DefaultAgendaTopic and the ConvAgendaItem are both supposed to be located on the actor. Your code has the ConvAgendaItem located on the DefaultAgendaTopic, which is—in turn—located on the actor.

I’m on mobile so I can’t run test cases right now to verify, but hopefully this helps narrow down the problem, at least.

3 Likes

Came here to say the same. These should both be located within the Actor object (or, inside an ActorState object if you’re using them):

+ Actor 'Bob'
;

++ DefaultAgendaTopic
;

++ ConvAgendaItem
;

One tip: When I build actors, I often will not use + to locate them inside a room. Rather, I put them at the end of the source file (or a separate file, if they’re complicated enough) and use @ to locate them:

Actor 'Bob' @livingRoom
;

+ DefaultAgendaTopic
;

+ ConvAgendaItem
;

I do this because it’s easy to lose track of containment levels when you start seeing +++ and ++++ in the code. Using @ to locate the actor reduces the level count by one, which helps a bit.

4 Likes

There’s no AgendaTopic per se, but there are the AgendaItem and ActorTopicEntry base classes for various conversation needs. A good starting point on actors in adv3lite is here.

4 Likes

Thanks for all the responses. It’s appreciated.

Perhaps I don’t understand the role of default agenda topic. Here’s the simplest example I could come up with that has all the moving parts. If I understand it, if I ask bob about the novel I should get “blah”, but I do not.

#charset "us-ascii"
#include <tads.h>
#include "advlite.h"

versionInfo: GameID
    IFID = 'aff39632-1f8e-4faa-b5f3-6f205b79c566'
    name = 'Your New Game Title'
    byline = 'by Your Name'
    htmlByline = 'by <a href="mailto:your-email@host.com">Your Name</a>'
    version = '1'
    authorEmail = 'Your Name <your-email@host.com>'
    desc = 'Put a brief "blurb" about your game here'
    htmlDesc = 'Put a brief "blurb" about your game here'
;

gameMain: GameMainDef
    /* Define the initial player character; this is compulsory */
        initialPlayerChar = me
;


startroom: Room 'The Starting Location'
    "Add your description here. "
;


+ novel : Thing 'novel'
;

+ me : Actor 'you'
;

+ Actor 'Bob' @startroom
;

++ DefaultAgendaTopic
    "blah"
;

++ ConvAgendaItem
    isReady = true
    initiallyActive = true
;
1 Like

Stepping back, things are little complicated with agendas. The + operator associate the agenda items with the Actor, but they don’t add them to the Actor’s agenda list. ConvAgendaItem.initiallyActive = true adds the item to the Actor’s agenda list, but you’re trying to use it with a DefaultAgendaTopic.

Here’s what I did (being a little more explicit, for debugging reasons):

+ Thing 'a novel'
;

+ Actor 'Bob'
;

++ defaultAgenda: DefaultAgendaTopic
  invokeItem() {
    "Default agenda item";
  }
;

++ ConvAgendaItem, PreinitObject
  invokeItem() {
    "ConvAgendaItem";
  }

    isReady = true
    initiallyActive = true

    execute() {
       // this adds the ConvAgendaItem to the DefaultAgendaTopic's agendaList
      defaultAgenda.addToAgenda(self);
    }
;

Here’s the results:

> ask bob about novel
ConvAgendaItem

The docs say this about DefaultAgendaTopic:

…if we manage the DefaultAgendaTopic’s agendaList properly (see below) the player should hardly ever see its topicResponse in any case.

That’s important to keep in mind. DefaultAgendaTopic is an AgendaManager, which means it’s more useful as a “container” of agendas the NPC is pursuing than a topic responder unto itself.

4 Likes

Thank you Jim for the detailed explanation!

Can you think of any case where DefaultAgendaTopic’s invokeItem is called and we see “Default agenda item”?

2 Likes

Unfortunately, not off the top of my head. While my next WIP has a lot of NPCs and conversation code, I don’t use DefaultAgendaTopic anywhere. My approach is to have several ActorState for each Actor, and (at most) one agenda associated with each state. This creates a “flow” in the conversation.

It might help you tell us what effect you’re trying to achieve (“When the player asks X, the NPC should respond Y, unless it’s about Z, in which case…”) There may be simpler ways of achieving what you want without a lot of agenda management.

1 Like

Honestly I’m not trying to achieve anything specific. I’m testing aspects of the library to understand how they work before I try and modify it a bit for my purposes.

My guess is DefaultAgendaTopic doesn’t work as intended (which is fine).

2 Likes

One of the things you can do to manage this is use a “bare” modify statement to set context. So for example this:

kitchen: Room 'Kitchen';
+bob: Actor 'Bob';
++DefaultAgendaTopic;

…can be re-written to split the declarations across two source files, one containing:

kitchen: Room 'Kitchen';
+bob: Actor 'Bob';

…and then another with…

modify bob;
+DefaultAgendaTopic;

…and so on.

I usually don’t use this for initial object placement (I usually put the location declaration in the object’s definition like you do), but I do often want to split up different types of Actor-specific objects (agendas, dialog, states, inventory) into their own files, and use a modify to handle that.

3 Likes

Jbj, I guess that you still haven’t experimented with the new ProxyActor class in a3Lite 1.6.x …

Best regards from Italy,
dott. Piergiorgio.

1 Like

Slick!

1 Like

Ok, I think have some answers here. Bear with me.

DefaultAgendaTopic is an AgendaManager and a DefaultAnyTopic. The second base class ensures that it’s invoked when all other responses fail, i.e., it’s a catch-all to prevent a boring default response (“Bob does not respond”).

However, it only invokes the DefaultAnyTopic functionality if its AgendaManager side cannot find an appropriate agenda to use for the response. What’s more, a DefaultAgendaTopic is only active if it has one or more agendas in its list:

active = (inherited && agendaList != nil && agendaList.length > 0)

This means it’s a catch-all, but only if it is managing one or more available agendas. Otherwise, it’s ignored (and adv3Lite is free to find another topic response, or use a boring built-in response).

So, to see the default response, you need to have (a) at least one agenda added to the DefaultAgendaTopic but (b) none of those agendas are isReady = true. (Setting an agenda’s isDone = true will drop it from the AgendaManager list, so those don’t count.)

I tried this:

+ novel: Thing 'a novel'
;

+ Actor 'Bob'
;

++ defaultAgenda: DefaultAgendaTopic
  topicResponse() {
    "Default agenda item";
  }
;

++ ConvAgendaItem, PreinitObject
  invokeItem() {
    "ConvAgendaItem";
  }

    isReady = novel.examined
    isDone = novel.isIn(gPlayerChar)
    initiallyActive = true

    execute() {
       // this adds the ConvAgendaItem to the DefaultAgendaTopic's agendaList
      defaultAgenda.addToAgenda(self);
    }
;

Note that the ConvAgendaItem is only ready when the novel is examined, and is done (disabled) when the player is holding the same.

Here’s the result:

> ask bob about novel
Default agenda item

> x novel
You see nothing special about the novel.

ConvAgendaItem

> ask bob about novel
ConvAgendaItem

> get novel
Taken. 

> ask bob about novel
Bob does not respond. 

Note that the ConvAgendaItem is activated the moment the novel was examined—that’s the magic of agendas vs. topics, the NPC attempting to “seize control of the conversation” in Eric Eve’s words. It remains active until the player picks up the novel. The final built-in response is because the DefaultAgendaTopic has no more available agenda items. If we add another non-ready ConvAgendaItem to its list, then we’d get the “Default agenda item” response.

So, what’s important here is that agendas should (in most cases) not simply be enabled with isReady = true and left that way, unless the NPC is really of a one-track mind. The intended case is for them to be enabled and disabled depending on changes in your game world. The DefaultAgendaTopic is intended to provide a response when the actor has some available agendas, but none are ready at the moment. (Its response could, for example, suggest the player do something to activate one of those agendas.)

Hope this helps.

4 Likes

This is something I’ve used before, too, in situations where ProxyActor doesn’t get the job done.

I don’t think jbg uses Adv3Lite at all, iirc…? I think he uses Adv3.

1 Like

You can elaborate more on these situations ? after the study of Infocom 'terp source, I shall return to the main WIP, starting the serious implementation of the two major NPC…

Best regards from Italy,
dott. Piergiorgio.

1 Like

NPC logic that is very complex but does not involve conversations. ProxyActor mostly collects conversation objects upon initialization, but if an NPC has complex non-conversation logic, then this class does not handle it, so modify is required once again.

EDIT: For a more specific example, an NPC which collects clues and observations while moving autonomously around the map, and takes actions based on these observations and the calculations of several linked state machines.

1 Like

Thanks. so (you have already looked at the first sketch of one NPC, I presume) is halfway the opposite of what I hope to do. The two NPC are, very prone to convo, but also have a certain degree of interaction with the environment when following the PC) so, the convo under proxy, and the rest in the npc.t files.

Best regards from Italy,
dott. Piergiorgio.

1 Like