# thoughtsuggs.t | documentation

    #charset "us-ascii"

    #include <tads.h>
    #include "advlite.h"

    /*
     *   *************************************************************************** thoughtsuggs.t
     *
     *   This module provides the Thought Sugestions extension for the adv3Lite library (c) 2024 Eric
     *   Eve
     *
     *   Version 1.0  07-Dec-2024
     *
     *   The Thought Suggestions extension changes the function of the THINK command so that it suggests
     *   a list of topics the player can THINK ABOUT (as the TOPICS command does for conversation
     *   topics). For this to work the Thoughts the player can think about must be located in a
     *   ThoughtManager object and provided with a name property.
     *
     *   The thoughtsuggs.t required thoughts.t and actor.t to be present in the game.
     *
     */

    /*
     *   The Thought Suggestions extension modifies the behaviour of the THINK action to display a list
     *   of suggested topics the player could think about.
     */
    modify Think
        execAction(cmd)
        {
            /* Note our current interlocutor. */
            local interlocutor = gPlayerChar.currentInterlocutor;

            try
            {

                /* Set the current interlocutor to nil. */
                gPlayerChar.currentInterlocutor = nil;

                /*
                 *   If we have an associated RuleBook and following it returns a non-nil value, assume
                 *   the RuleBook has dealt with the THINK command and stop there, unless it returns
                 *   true, in which case assume that we want to list suggestions as well.
                 */
                local ret = null;

                if(ruleBook && (ret = ruleBook.follow()) != null)
                {
                    if(suggestAlways)
                        "<.p>";
                    else
                        return;
                }

                /*
                 *   If a TboughtManager object has been defined in this game, call its
                 *   showSuggections() method to list suggested topics to think about.
                 */
                if(libGlobal.thoughtManagerObj != nil)
                    libGlobal.thoughtManagerObj.showSuggestions();

                /*
                 *   Otherwise show our default response if no rulebook has
                 *   handled the THINK command already.
                 */
                else if(ret == null)
                    sayDefaultThought();
            }
            finally
            {
                /* Restore the current interlocutor. */
                gPlayerChar.currentInterlocutor = interlocutor;
            }
        }

        suggestAlways = nil
    ;

    /*
     *   The Lister for listing suggested topics to THINK ABOUT. We base it on suggestedTopicLister,
     *   since most of the logic is the same.
     */
    thoughtSuggestionLister: suggestedTopicLister
        /* The message to display if there are no thought topics to suggest. */
        showListEmpty(explicit)
        {
            gCommand.actor = gPlayerChar;
            if(explicit)
                DMsg(no thought in mind, '{I} {have} nothing in mind to think about just {then}. ');
        }

        /*
         *   Override suggestedTopicLister's list of TypeInfo to the values relevant to Thoughts.
         *.
         *   The first element of the list is a pointer to the list property to use on this
         *   lister object to hold the particular sublist. The second element of each list is a property
         *   pointer used to identify which sublist a Thought belongs in, according to its own
         *   includeInList property. The third element is the type of topic entry a topic entry should
         *   be suggested as if it is explicitly requested in its suggestAs property. The fourth element
         *   is the text to use when introducing the corresponding section of the list (or nil if no
         *   introductory text is required).
         */
        typeInfo = [
            [&thoughtList, &thoughtTopics, Thought, &thinkPrefix]
        ]

        /* Our list of Thoughts to suggest. This will be built by thoughtSuggestionLister. */
        thoughtList = []

        /* The text to introduce our list of suggested Thoughts, following "You could ". */
        thinkPrefix = BMsg(think about, 'think about ')

    ;

    /*
     *   Modifications to the TboughtManager class to allow it to work witht the Tbought Suggestions
     *   extenstion.
     */
    modify ThoughtManager

        /* Display a list of topics the player can THINK ABOUT */
        showSuggestions()
        {
            /* Set up a local lst variable to hold the list of Think Abouts we want to display. */
            local lst = [];

            /*
             *   Get a list of all our active thoughts whose curiosity has been aroused but not
             *   satisfied.
             */
            lst = thoughtList.subset({x: x.isActive && x.curiosityAroused && !x.curiositySatisfied});

            /* Reduce the list to topics the PlayerCharacter knows about */
            lst = lst.subset({x: x.matchObj == nil || valToList(x.matchObj)[1].known});

            /*
             *   Use the thoughtSuggestionLister to list the thourhs the player might want to ask about.
             */
            thoughtSuggestionLister.show(lst);

        }

        /* Carry out our Preinitialization. */
        execute()
        {
            /* Carry out our inherited Preinitialization. */
            inherited();

            /* Initialize all our Thoughts. */
            foreach(local t in thoughtList)
                t.initializeTopicEntry();
        }
    ;

    modify Thought
        /*
         *   A Thought should be suggested as a Thought by thoughtSuggestionLister; we need to specify
         *   that here since suggestedTopicLister, from which thoughtSuggestionLister inhgerits, needs
         *   this information.
         */
        suggestAs = Thought

        /*
         *   The listOrder can be used to determine the order in which Thought suggestions are listed.
         *   Thoughts with a lower listOrder will be listed before Tboughts with a higher listOrder. By
         *   default we give all Thoughts a listOrder of 100.
         */
        listOrder = 100

        /*
         *   An expression that should evaluate to true when we want this Thought to be suggested. Note
         *   that both curiosityAroused and curiositySatisfied need to be overridden by expressions or
         *   methods) in game code if something other then their default values (or true and nil
         *   respectively) are needed.
         */
        curiosityAroused = true

        /*
         *   An expression that should evaluate to true when we no lomger want this Thought to be
         *   suggested. This needs to be overriden by game code if desired; the extension makes no
         *   attempt to update curiositySatisifed to true when, say, a Thought topic has been suggested
         *   once or so many times, as each game will probably want to handle this in a different way.
         */
        curiositySatisfied = nil

        /*
         *   The name to be displayed if you want this Thought to be suggested in response to a THINK
         *   command. This should be something that would match the vocab of the Topic associated with
         *   this Thought. Alternatively, autoName can be set to true to have the name set to the name
         *   of the Topic (or Thing) this Thought matches.
         */
        name = nil

        /*
         *   If autoName is true, the library will attempt to define the name property from our
         *   associated Topic, provided name hasn't already been defined.
         */
        autoName = nil

        /* Initialize this Thought (this is actually called at preinit) */
        initializeTopicEntry()
        {
            /*
             *   If our autoname property is true, construct our name (for use in
             *   suggesting this TopicEntry) provided we have something to construct
             *   it from.
             */
            if(autoName && matchObj != nil && name is in (nil, ''))
                buildName();
        }

         /*
         *   Construct the name of this ActorTopicEntry by using the theName
         *   property of our first matchObj.
         */
        buildName() { name = valToList(matchObj)[1].theName; }
    ;

    /*
     *   A PreParsr that traps numerical input (e.g. a command consisting purely of an integer, such as
     *   2), and translates it into the THINK ABOUT command in the latest list of enumerated thought
     *   suggesstions.
     */

    enumTboughtSuggestionsPreparser: StringPreParser
        doParsing(str, which)
        {
            /*
             *   We only want to modify str here if this is a new command
             *   and the suggestedTopicLister's enumerateSuggestions property is set to true.
             */
            if(which == rmcCommand && thoughtSuggestionLister.enumerateSuggestions)
            {
                /* Try converting str to an integer */
                local num = toInteger(str);

                /*
                 *   If we have a number and that number is in the range of the number of topic
                 *   suggestions listed then replace str with the corresponding conversational command.
                 */
                if(num && num <= suggestionEnumerator.count && num > 0)
                {
                    /*
                     *   Change str to the corresponding item in suggestionEnumerator's suggestion list.
                     */
                    str = suggestionEnumerator.suggestionList[num];

                    /*
                     *   Echo the new command back to the player so the player can see what's now being
                     *   executed.
                     */
                    "<.inputline>\^<<str>><./inputline>\n";
                }
            }

            /* Return our string, modified or unmodified as the case may be. */
            return str;
        }
    ;

Adv3Lite Library Reference Manual
Generated on 08/12/2025 from adv3Lite version 2.2.2