Skip to content

Custom Daily

Idle edited this page Dec 12, 2024 · 25 revisions

You can create custom dailies for your world the same way the built-in dailies are made, it works similar to a foundry macro, the code you enter in the text field of the Register Custom Dailies menu represents the inside of an asynchronous function that must return a Daily object.

Daily Object format

Some comments on the daily object

return {
    /**
     * REQUIRED
     * The unique key for your custom daily, those are isolated from the
     * built-in daily keys.
     */
    key: "my-custom-daily",
    /**
     * CONDITIONALLY REQUIRED
     * This will completely remove the daily from the actor if it returns false.
     * NOTE: required if no 'items' are provided.
     */
    condition: (actor) => true,
    /**
     * CONDITIONALLY REQUIRED
     * An array of slug + uuid to identify which embedded items need to be
     * retrieved from the character, the 'required' flag makes an item mandatory
     * for the functionment of the daily.
     * An 'items' object parameter is forwarded in all the functions of the daily.
     * NOTE: required if no 'condition' is provided.
     */
    items: [
        {
            slug: "item",
            uuid: "Compendium.xxx.Item.xxx",
            required: true,
        },
    ],
    /**
     * OPTIONAL
     * Can be a string or a function that returns a string.
     * NOTE: because the item was 'required', we are sure that it exists on the
     * character and can be accessed without doing extra check.
     */
    label: (actor, items) => items.item.name,
    /**
     * OPTIONAL
     * Called in the first stage of the daily and returns an object of arbitrary
     * data that will be forwarded to the 'rows' and 'process' functions
     * as 'custom' argument.
     * This is useful if want to avoid recomputing the same data twice.
     */
    prepare: (actor, items) => {
        return {
            uselessVariable: "plop",
        };
    },
    /**
     * REQUIRED
     * This is where you define the different rows that appears in the interface.
     * It returns an array of 'DailyRow' of the different available types.
     * A 'rows' object parameter is forwarded to the 'process' function, its
     * content depends on the row type.
     * NOTE: 'select' and 'random' rows with an empty 'options' array will be
     * removed.
     * NOTE: if only one row is provided, it will appear at the top of the daily
     * interface with the other single row dailies and its label will be the
     * daily label instead of the row label.
     */
    rows: (actor, items, custom) => {
        const options = [
            { value: "no", label: "" },
            { value: "yes", label: items.item.name },
        ];

        return [
            {
                type: "select",
                slug: "selection",
                label: custom.uselessVariable,
                options: options,
            },
        ];
    },
    /**
     * REQUIRED
     * This is the part that actually modify the character, helper functions are
     * provided to both avoid making dozens of updates on the character and
     * to let the module handle redundant and important mechanics of the daily,
     * these paired with the 'utils' functions should cover most of what a
     * custom daily needs.
     */
    process: ({ actor, rows, messages, addItem }) => {},
    /**
     * OPTIONAL
     * Called during 'Rest for the Night' to cleanup things that the module
     * can't handle itself.
     * This function should rarely be needed if you use the provided
     * helpers in the 'process', since the module will automatically revert
     * anything it did when using those.
     * NOTE: to give some perspective, the only built-in daily that needs to use
     * this is the 'familiar' one because it needs to remove the abilities on
     * the familiar actor.
     */
    rest: ({ actor, removeItem }) => {},
    /**
     * OPTIONAL
     * Use to register daily specifig configs.
     * Those will appear in the `Config` menu of the daily preparation interface.
     * Returns an array of input related configs
     */
    config: (actor) => {
        return [
            {
                type: "checkbox",
                /**
                 * input element name attribute
                 */
                name: "my-config",
                /**
                 * OPTIONAL
                 */
                value: true,
                label: "My Module Config",
            },
        ];
    },
    /**
     * OPTIONAL
     * Called during the daily preparation process right after all the items
     * from all the dailies were added to the character and before the items update/delete happen.
     * You can use the same helpers than in the `process` function except the ones that add items
     * or rules to the character.
     */
    afterItemAdded: ({ addedItems, setExtraFlags }) => {
        const myFlag = addedItems.filter((item) => item.id);
        setExtraFlags({ myFlag });
    },
};

Note

All the functions in the daily can be asynchronous.

Custom Daily context

In the context of the custom daily function are exposed the following

utils

This object contains tons of function helpers used to create the built-in dailies (and more) making the most common tasks taken inside a daily easier, you can find the source for all the utility functions here.

createComboSkillDaily

This function creates a daily object to allow the character to temporarily improve the proficiency of a skill (or create a lore skill), this is used to create the Ageless Spirit, Ancient Memories and Flexible Studies dailies, you can find its source here

createLoreSkillDaily

This function creates a daily object to allow the character to temporarily gain a lore skill, this is used to create the Quick Study daily, you can find its source here

createLanguageDaily

This function creates a daily object to allow the character to gain a temporary language, this is used to create the Ancestral Linguistics and Bort's Blessing dailies, you can find its source here

createResistanceDaily

This function creates a daily object to allow the character to gain a temporary resistance, this is used to create the Elementalist Dedication and Ganzi Heritage dailies, you can find its source here

createScrollChainDaily

This function creates a daily object to allow the character to create temporary spell scrolls based on a series of 3 feats and its level, this is used to create the Scroll Esoterica and Basic Scroll Cache dailies, you can find its source here

Third Party Modules

Modules can register their own custom dailies without having to add them to the world setting, dailies need to be registered after the init hook, to do so you need to use

game.modules.get("pf2e-dailies")?.api.registerCustomDailies(dailies: Daily[])

Because custom dailies are normally just strings representing the inside of an asynchronous function, they can have parameters injected in their context, the most useful being utils which is used in almost all stages of a daily; The dailies registered with registerCustomDailies being actual daily objects, they cannot enjoy that same convenience and need to look for it in the API

game.modules.get("pf2e-dailies")?.api.utils;