SayQuery is my new ADV3 Obsession

Hey, adv3 folks, have you tripped over EE’s SayQuery module ? Its simple goals are to 1) provide access to non-ask/tell/give/show dialogue (outside of ConvNodes) and 2) provide optional hyperlink or numerical inputs to suggested dialogue options. Both of these are AMAZINGLY powerful and useful. 5 :star: would recommend.

As my WIP is a patchwork (or more generously, an anthology) of different play styles, I am only now, three years in, playing with suggested dialogue. SayQuery is just an indispensable add-on for that, IMO. As long as you remember to include the SayQuery.h header it just works.

Now, because I am ME, I did end up tweaking a few things. These should not be considered shortcomings, but breadcrumbs for future SQ enthusiasts like myself.

Three things I ended up tweaking were: 1) modifying the suggestion list preamble; 2) enabling fullName option customization rather than ‘say that <<name>>’; and 3) dynamically enabling suggestions at all

By way of explanation, the stock dialogue suggestion is along the lines of

(You could say that you love him, that you hate him, or
that you never think of him at all.)

“You could ” is the preamble, and each option builds around a ‘name’ property of you love him and so on. In the interests of relative brevity I’m not going to go into the powerful pattern matching flexibility this module gives you, but focus just on that messaging.

  1. modifying list preamble. (Change independent of SayQuery.) The intent of suggestions is that they are non-exclusive, that other topics are still fair game. “You could…” certainly implies that but I wanted something a little stronger. Wahlaa:
modify SuggestedTopicLister
    showListPrefixWide(cnt, pov, parent) {
        // add the asking and target actors as global message parameters
        gMessageParams(askingActor, targetActor);

        // show the prefix; include a paren if not in explicit mode
        "<<isExplicit ? '' : '('>>If {you askingActor/he} {have} nothing
            else to say, {you askingActor/he} could ";
    }
;

for a larger game/integration of this capability, you might want to base the message on a SuggestedTopicLister parameter, or perhaps a parameter of parent, with appropriate ‘default’ detection. This would enable per-encounter messaging.

  1. enabling fullName option customization rather than ‘say that <<name>>’ By default fullName is constructed from the name property. This has the effect that it presumes you want the message to be formatted as ‘say that [something something]’. Suppose you wanted something different? Instead of say that you love him you want to profess your love? This does require some tweaks to the SayQuery suggestionSayGroup, here because I am using the html highlighting from the module’s HyperEnumSugg capability. Without the module, the changes are analagous, but not the same. To wit:
modify suggestionSayGroup
    groupPrefix() {
        if(tellStyle)
            "tell {it targetActor/him} ";
        // JJMcC: Some options will use fullName, which includes unique verbs
        //     so comment out below
        // else "say ";
    }
    showGroupItem(sublister, obj, options, pov, infoTab) {
        // JJMcC:  if fullName not overriden, use individual "say that" prefix
        local fullNameOverridden = nil;
        if (dataType(obj.fullName) != TypeSString) {
            if (obj.name.startsWith('that ')) "say ";
            else "say that ";
        } else
            fullNameOverridden = true;
        obj.noteSuggestion();

        // JJMcC Below changes specific to HyperEnumSugg
        if(gameMain.enumerateSuggestedTopics)
            "[<<obj.suggestionNumber>>] ";

        // JJMcC situationally use fullName
        if(gameMain.hyperlinkSuggestedTopics) {
            if (fullNameOverridden) say(obj.htmlFullName);
            else say(obj.htmlName);
        } else {
            if (fullNameOverridden) say(obj.fullName);
            else say(obj.name);
        }
    }
;
  1. dynamically enabling suggestions at all. Suggestions have the potential to tunnel-vision a player on the suggested topics only. One way to mitigate this would be to only bring up suggestions after a player has tried to ask/tell and only received the default 'NPC has no response response. More generally you might find it convenient to programmatically control when to provide suggestions and when not. Here’s a way!
modify conversationManager
    suggestionsEnabled = gRevealed('suggestOkNow')
    topicInventoryDaemon() {
        if (suggestionsEnabled) inherited;
    }
;
[elsewhere in code, under an NPC]
+ DefaultAskTopic
    "NPC has nothing to say about that.  <.reveal suggestOkNow><.topics>"
;

What does all this tinkering do for you? Well, when provisioning non ask/tell conversation topics like so (with very simple matching for demo purposes)

+ SayTopic, SuggestedSayTopic
    ['profess', '(your|my)', 'love|admiration', '(for)', '(him)']
    "He tears up a little.  "
    fullName = 'profess your love'
    keywordsReqd = 1
    curiositySatisfied = nil
;
+ SayTopic, SuggestedSayTopic
    ['vent', '(your|my)', 'hatred', '(for)', '(him)']
    "He recoils in hurt surprise.  "
    fullName = 'vent your hatred'
    keywordsReqd = 1
    curiositySatisfied = nil
;
+ SayTopic, SuggestedSayTopic
    ['shrug', '(your|my)', 'indifference', '(for|to)', '(him)']
    "He slumps in depressed resignation.  Then joins some incel chat groups. "
    fullName = 'shrug your indifference'
    keywordsReqd = 1
    curiositySatisfied = nil
;

You get output like so

(If you have nothing else to say, you could profess your love,
vent your hatred, or shrug your indifference.)

EDIT: so many typos

3 Likes