static void aNRG2_set_str_j3(void) {
    static u8 choume_str[] = { 'Q', 'A', 'B', 'C', 'D', 'E', 'F' };
    mMsg_Window_c* msg_p = mMsg_Get_base_window_p();
    mQst_errand_c* errand_p = mQst_GetFirstJobData();
    AnmPersonalID_c* to_id_p = &errand_p->recipient;
    int idx = mNpc_SearchAnimalinfo(Save_Get(animals), to_id_p->npc_id, ANIMAL_NUM_MAX);
    u8 str[ANIMAL_NAME_LEN];

    if (idx != -1) {
        /* Set msg string 3 & 4 to acre Z & X respectively */
        Anmhome_c* home_p = &Save_Get(animals[idx]).home_info;

        mMsg_Set_free_str(msg_p, mMsg_FREE_STR3, &choume_str[home_p->block_z], 1);
        mFont_UnintToString(str, sizeof(str), home_p->block_x, sizeof(str), TRUE, FALSE, TRUE);
        mMsg_Set_free_str(msg_p, mMsg_FREE_STR4, str, sizeof(str));
    }

    mNpc_GetNpcWorldNameAnm(str, to_id_p);
    mMsg_Set_free_str_cl(msg_p, mMsg_FREE_STR5, str, sizeof(str), 1);
}

static void aNRG2_set_str_j4(void) {
    int bx;
    int bz;
    u8 str[1];

    /* Set recipient home acre */
    aNRG2_set_str_j3();
    /* Set post office acre string */
    mFI_BlockKind2BkNum(&bx, &bz, mRF_BLOCKKIND_POSTOFFICE);
    mFont_UnintToString(str, sizeof(str), bx, sizeof(str), TRUE, FALSE, TRUE);
    /* We only care about the X acre since the post office is always in the A row */
    mMsg_SET_FREE_STR(mMsg_FREE_STR6, str, sizeof(str));
}

typedef void (*aNRG2_SET_STR_PROC)(void);

static void aNRG2_set_str_proc(void) {
    static aNRG2_SET_STR_PROC process[] = {
        (aNRG2_SET_STR_PROC)&none_proc1,
        (aNRG2_SET_STR_PROC)&none_proc1,
        &aNRG2_set_str_j3,
        &aNRG2_set_str_j4,
        &aNRG2_set_str_j3,
        &aNRG2_set_str_j3,
        (aNRG2_SET_STR_PROC)&none_proc1,
        &aNRG2_set_str_j4,
        &aNRG2_set_str_j3,
        (aNRG2_SET_STR_PROC)&none_proc1,
        (aNRG2_SET_STR_PROC)&none_proc1,
    };

    mQst_errand_c* errand_p = mQst_GetFirstJobData();
    int idx = errand_p->base.quest_kind - mQst_ERRAND_FIRSTJOB_CHANGE_CLOTH;

    /* Set the current job strings, index is job quest idx relative to first job */
    (*process[idx])();
}

static void aNRG2_set_possession(void) {
    // clang-format off
    static mActor_name_t set_item[] = {
        ITM_CLOTH016,
        ITM_WHITE_PANSY_BAG,
        EMPTY_NO,
        ITM_PAPER55,
        EMPTY_NO,
        ITM_AXE,
        EMPTY_NO,
        ITM_PAPER55,
        ITM_AXE,
        EMPTY_NO,
        EMPTY_NO,
    };
    // clang-format on
    mQst_errand_c* errand_p = mQst_GetFirstJobData();
    u32 job_kind = errand_p->base.quest_kind - mQst_ERRAND_FIRSTJOB_CHANGE_CLOTH;

    if (job_kind == aNRG2_JOB2) {
        int i;
        /* Give player 7 random flower bags */
        for (i = 0; i < 7; i++) {
            mActor_name_t item = ITM_WHITE_PANSY_BAG + RANDOM(9);

            mPr_SetFreePossessionItem(Now_Private, item, mPr_ITEM_COND_NORMAL);
        }

        /* Give player 3 saplings */
        for (i = 0; i < 3; i++) {
            mPr_SetFreePossessionItem(Now_Private, ITM_SAPLING, mPr_ITEM_COND_NORMAL);
        }
    } else {
        switch (job_kind) {
            case aNRG2_JOB3:
            case aNRG2_JOB5:
                /* Set the random errand item with quest condition */
                mPr_SetFreePossessionItem(Now_Private, errand_p->item, mPr_ITEM_COND_QUEST);
                break;
            case aNRG2_JOB1:
            case aNRG2_JOB4:
            case aNRG2_JOB7:
            case aNRG2_JOB8:
                /* Set the static job item with normal condition */
                mPr_SetFreePossessionItem(Now_Private, set_item[job_kind], mPr_ITEM_COND_NORMAL);
                break;
            case aNRG2_JOB2:
            case aNRG2_JOB6:
            case aNRG2_JOB9:
            default:
                /* Set the static job item with quest condition */
                mPr_SetFreePossessionItem(Now_Private, set_item[job_kind], mPr_ITEM_COND_QUEST);
                break;
            case aNRG2_JOB10:
            case aNRG2_JOB11:
                break;
        }
    }
}

static int aNRG2_check_job_start(void) {
    mQst_errand_c* errand_p = mQst_GetFirstJobData();
    int res = FALSE;
    u32 free_slots = mPr_GetPossessionItemSum(Now_Private, EMPTY_NO);

    switch (errand_p->base.quest_kind) {
        case mQst_ERRAND_FIRSTJOB_PLANT_FLOWER:
            /* Need at least 10 inventory slots free for the planting chore */
            if (free_slots >= 10) {
                res = TRUE;
            }
            break;
        case mQst_ERRAND_FIRSTJOB_POST_NOTICE:
        case mQst_ERRAND_FIRSTJOB_INTRODUCTIONS:
        case mQst_ERRAND_FIRSTJOB_OPEN:
            /* These chores have no items and thus can always be started */
            res = TRUE;
            break;
        default:
            /* Default requires at least one free inventory slot */
            if (free_slots > 0) {
                res = TRUE;
            }
            break;
    }

    return res;
}

/* Is this a typo of setup? */
static void aNRG2_stepup_j1(u32 kind, NPC_RCN_GUIDE2_ACTOR* rcn_guide2) {
    mQst_errand_c* errand_p = mQst_GetFirstJobData();

    /* Job 1: change into 'work clothes' */
    mQst_SetFirstJobChangeCloth(errand_p, ITM_CLOTH016);
}

static void aNRG2_stepup_j2(u32 kind, NPC_RCN_GUIDE2_ACTOR* rcn_guide2) {
    mQst_errand_c* errand_p = mQst_GetFirstJobData();

    /* Job 2: plant flower seeds & tree saplings */
    mQst_SetFirstJobSeed(errand_p);
}

static void aNRG2_stepup_j3(u32 kind, NPC_RCN_GUIDE2_ACTOR* rcn_guide2) {
    /* List of 'no good' furniture, seemingly only ones you can walk on? */
    static mActor_name_t ng_list[] = { FTR_MANHOLE_COVER, FTR_BATH_MAT };
    mQst_errand_c* errand_p;
    AnmPersonalID_c* anm_pid_p;
    mActor_name_t ftr;
    u32 free_idx;

    /* Get first job quest data */
    errand_p = mQst_GetFirstJobData();

    /* Get first free inventory slot index */
    free_idx = mPr_GetPossessionItemIdx(Now_Private, EMPTY_NO);

    /* Get an unused target villager for delivery target */
    anm_pid_p = mNpc_GetOtherAnimalPersonalID(errand_p->info.first_job.used_ids, errand_p->info.first_job.used_num);

    /* Roll random ABC list furniture to be delivered */
    mSP_SelectRandomItem_New(NULL, &ftr, 1, ng_list, ARRAY_COUNT(ng_list), mSP_KIND_FURNITURE, mSP_LISTTYPE_ABC, FALSE);

    /* Job 3: deliver furniture */
    mQst_SetFirstJobFurniture(errand_p, anm_pid_p, ftr, free_idx);
}

static void aNRG2_stepup_j4(u32 kind, NPC_RCN_GUIDE2_ACTOR* rcn_guide2) {
    mQst_errand_c* errand_p;
    AnmPersonalID_c* anm_pid_p;

    // Get first job quest data
    errand_p = mQst_GetFirstJobData();

    // Get an unused target villager for letter recipient
    anm_pid_p = mNpc_GetOtherAnimalPersonalID(errand_p->info.first_job.used_ids, errand_p->info.first_job.used_num);

    // Force a memory with the animal in the event the player hasn't spoken to them yet
    // This could happen if an animal moves in before the chore is started,
    // but after the introductions sequence is finished.
    // This prevents the case where the recipient would not be listed
    // in the recipient menu despite being assigned by Nook.
    mNpc_SetAnimalPersonalID2Memory(anm_pid_p);

    // Job 4: send letter
    if (kind == aNRG2_JOB4) {
        mQst_SetFirstJobLetter(errand_p, anm_pid_p);
    } else {
        mQst_SetFirstJobLetter2(errand_p, anm_pid_p);
    }

    // Allow Nook to remind the player about this chore
    rcn_guide2->can_ask_again_flag = TRUE;
}

static void aNRG2_stepup_j5(u32 kind, NPC_RCN_GUIDE2_ACTOR* rcn_guide2) {
    mQst_errand_c* errand_p;
    AnmPersonalID_c* anm_pid_p;
    mActor_name_t ftr;
    u32 free_idx;

    /* Get first job quest data */
    errand_p = mQst_GetFirstJobData();

    /* Get first free inventory slot index */
    free_idx = mPr_GetPossessionItemIdx(Now_Private, EMPTY_NO);

    /* Get an unused target villager for delivery target */
    anm_pid_p = mNpc_GetOtherAnimalPersonalID(errand_p->info.first_job.used_ids, errand_p->info.first_job.used_num);

    /* Roll random ABC list carpet to be delivered */
    mSP_SelectRandomItem_New(NULL, &ftr, 1, NULL, 0, mSP_KIND_CARPET, mSP_LISTTYPE_ABC, FALSE);

    /* Job 5: deliver carpet */
    mQst_SetFirstJobCarpet(errand_p, anm_pid_p, ftr, free_idx);
}

static void aNRG2_stepup_j6(u32 kind, NPC_RCN_GUIDE2_ACTOR* rcn_guide2) {
    mQst_errand_c* errand_p;
    u32 free_idx;

    // Get first job quest data
    errand_p = mQst_GetFirstJobData();

    // Get the first free inventory slot
    free_idx = mPr_GetPossessionItemIdx(Now_Private, EMPTY_NO);

    // Job 5: deliver axe
    if (kind == aNRG2_JOB6) {
        mQst_SetFirstJobAxe(errand_p, &errand_p->info.first_job.used_ids[1], ITM_AXE, free_idx);
    } else {
        mQst_SetFirstJobAxe2(errand_p, &errand_p->info.first_job.used_ids[1], ITM_AXE, free_idx);
    }
}

static void aNRG2_stepup_j7(u32 kind, NPC_RCN_GUIDE2_ACTOR* rcn_guide2) {
    mQst_errand_c* errand_p = mQst_GetFirstJobData();

    /* Job 7: post on notice board */
    mQst_SetFirstJobNotice(errand_p);
}

static void aNRG2_stepup_j10(u32 kind, NPC_RCN_GUIDE2_ACTOR* rcn_guide2) {
    mQst_errand_c* errand_p = mQst_GetFirstJobData();

    /* Job 10: introductions */
    mQst_SetFirstJobHello(errand_p);
}

static void aNRG2_stepup_j11(u32 kind, NPC_RCN_GUIDE2_ACTOR* rcn_guide2) {
    mQst_errand_c* errand_p = mQst_GetFirstJobData();

    /* Job 11: open quest */
    mQst_SetFirstJobOpenQuest(errand_p);
}

typedef void (*aNRG2_STEPUP_PROC)(u32, NPC_RCN_GUIDE2_ACTOR*);

static void aNRG2_stepup_job(NPC_RCN_GUIDE2_ACTOR* rcn_guide2, u32 job_kind) {
    // clang-format off
    static aNRG2_STEPUP_PROC stepup_job_proc[] = {
        &aNRG2_stepup_j1,
        &aNRG2_stepup_j2,
        &aNRG2_stepup_j3,
        &aNRG2_stepup_j4,
        &aNRG2_stepup_j5,
        &aNRG2_stepup_j6,
        &aNRG2_stepup_j7,
        &aNRG2_stepup_j4,
        &aNRG2_stepup_j6,
        &aNRG2_stepup_j10,
        &aNRG2_stepup_j11,
    };
    // clang-format on

    mQst_errand_c* errand_p = mQst_GetFirstJobData();

    if (errand_p->base.progress == 1) {
        (*stepup_job_proc[job_kind])(job_kind, rcn_guide2);
        aNRG2_set_str_proc();
    }
}

static void aNRG2_setup_job(int job_kind) {
    // clang-format off
    static u32 kind[] = {
        mQst_ERRAND_FIRSTJOB_CHANGE_CLOTH,
        mQst_ERRAND_FIRSTJOB_PLANT_FLOWER,
        mQst_ERRAND_FIRSTJOB_DELIVER_FTR,
        mQst_ERRAND_FIRSTJOB_SEND_LETTER,
        mQst_ERRAND_FIRSTJOB_DELIVER_CARPET,
        mQst_ERRAND_FIRSTJOB_DELIVER_AXE,
        mQst_ERRAND_FIRSTJOB_POST_NOTICE,
        mQst_ERRAND_FIRSTJOB_SEND_LETTER2,
        mQst_ERRAND_FIRSTJOB_DELIVER_AXE2,
        mQst_ERRAND_FIRSTJOB_INTRODUCTIONS,
        mQst_ERRAND_FIRSTJOB_OPEN,
    };
    // clang-format on

    mQst_errand_c* errand_p = mQst_GetFirstJobData();

    errand_p->base.quest_kind = kind[job_kind];
    errand_p->base.progress = 1;
}

static void aNRG2_say_hello_talk_proc(NPC_RCN_GUIDE2_ACTOR* rcn_guide2) {
    // clang-format off
    static int job_start_msg_no[] = {
        0x07F1,
        0x07F6,
        0x07FB,
        0x0802,
        0x080C,
        0x0813,
        0x0818,
        0x0802,
        0x0813,
        0x0821,
        0x0827,
    };
    // clang-format on

    // clang-format off
    static int job_start_refuse_msg_no[] = {
        0x07F0,
        0x07F5,
        0x07FA,
        0x07FA,
        0x07FA,
        0x07FA,
        0x0818,
        0x07FA,
        0x07FA,
        -1,
        -1,
    };
    // clang-format on

    static int next_talk_idx[] = { aNRG2_TALK_DEMO_START_WAIT, aNRG2_TALK_TALK_END_WAIT };

    mMsg_Window_c* msg_p;
    mQst_errand_c* errand_p;
    int msg_no;
    int talk_idx;
    int job_kind;

    msg_p = mMsg_Get_base_window_p();
    errand_p = mQst_GetFirstJobData();
    if (errand_p->base.progress == 1) {
        job_kind = errand_p->base.quest_kind - mQst_ERRAND_FIRSTJOB_CHANGE_CLOTH;
        if (aNRG2_check_job_start() == TRUE) {
            /* The next job can be started */

            // Initial setup
            aNRG2_stepup_job(rcn_guide2, job_kind);
            // Set quest items if necessary
            aNRG2_set_possession();
            // Setup params
            msg_no = job_start_msg_no[job_kind];
            rcn_guide2->next_think_idx = aNRG2_THINK_TALK_START_WAIT;
            talk_idx = 0;
        } else {
            /* The next job can't be started */
            msg_no = job_start_refuse_msg_no[job_kind];
            rcn_guide2->next_think_idx = aNRG2_THINK_JOB_START_WAIT;
            talk_idx = 1;
        }

        mMsg_Set_continue_msg_num(msg_p, msg_no);
        aNRG2_change_talk_proc(rcn_guide2, next_talk_idx[talk_idx]);
    } else {
        /* We're still in the middle of a job? */
        rcn_guide2->next_think_idx = aNRG2_THINK_TALK_START_WAIT;
        mMsg_Set_CancelNormalContinue(msg_p);
        aNRG2_change_talk_proc(rcn_guide2, aNRG2_TALK_TALK_END_WAIT);
    }
}

static void aNRG2_say_hello_sp_talk_proc(NPC_RCN_GUIDE2_ACTOR* rcn_guide2) {
    /* Special message on first meeting at shop if player is already wearing uniform */
    mMsg_SET_CONTINUE_MSG_NUM(0x0837);
    aNRG2_change_talk_proc(rcn_guide2, aNRG2_TALK_SAY_HELLO_SP2);
}

static void aNRG2_say_hello_sp2_talk_proc(NPC_RCN_GUIDE2_ACTOR* rcn_guide2) {
    if (mMsg_GET_MSG_NUM() == 0x0837) {
        aNRG2_say_hello_talk_proc(rcn_guide2);
    }
}

static void aNRG2_cloth_chk_talk_proc(NPC_RCN_GUIDE2_ACTOR* rcn_guide2) {
    mQst_errand_c* errand_p = mQst_GetFirstJobData();

    if (errand_p->base.progress == 1) {
        rcn_guide2->next_think_idx = aNRG2_THINK_JOB_START_WAIT;
    } else {
        rcn_guide2->next_think_idx = aNRG2_THINK_TALK_START_WAIT;
    }

    aNRG2_change_talk_proc(rcn_guide2, aNRG2_TALK_TALK_END_WAIT);
}

static void aNRG2_demo_start_wait_talk_proc(NPC_RCN_GUIDE2_ACTOR* rcn_guide2) {
    /* List of display items for each job */
    static mActor_name_t itemNo[] = {
        ITM_CLOTH016,        /* work uniform */
        ITM_WHITE_PANSY_BAG, /* flower bag */
        FTR_FAN,             /* furniture */
        ITM_PAPER55,         /* simple paper */
        ITM_CARPET00,        /* carpet */
        ITM_AXE,             /* axe */
        EMPTY_NO,            /* no item */
        ITM_PAPER55,         /* simple paper */
        ITM_AXE,             /* axe */
        EMPTY_NO,            /* no item */
        EMPTY_NO,            /* no item */
    };

    int order = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 1);

    if (order == 4) {
        mQst_errand_c* errand_p = mQst_GetFirstJobData();
        u32 kind = errand_p->base.quest_kind - mQst_ERRAND_FIRSTJOB_CHANGE_CLOTH;

        /* Set params for hand over item */
        mDemo_Set_OrderValue(mDemo_ORDER_NPC1, 0, itemNo[kind]);
        mDemo_Set_OrderValue(mDemo_ORDER_NPC1, 1, 7);
        mDemo_Set_OrderValue(mDemo_ORDER_NPC1, 2, 0);
        /* Don't let the player continue dialog */
        mMsg_SET_LOCKCONTINUE();
        aNRG2_change_talk_proc(rcn_guide2, aNRG2_TALK_DEMO_END_WAIT);
    }
}

static void aNRG2_demo_end_wait_talk_proc(NPC_RCN_GUIDE2_ACTOR* rcn_guide2) {
    /* Wait for the hand over process item to start */
    if (rcn_guide2->npc_class.action.idx == 10 && Common_Get(clip).handOverItem_clip->master_actor != NULL) {
        aNRG2_change_talk_proc(rcn_guide2, aNRG2_TALK_DEMO_END_WAIT2);
    }
}

static void aNRG2_demo_end_wait2_talk_proc(NPC_RCN_GUIDE2_ACTOR* rcn_guide2) {
    /* Wait for the hand over item process to finish */
    if (Common_Get(clip).handOverItem_clip->master_actor == NULL) {
        /* Allow player to continue dialog */
        mMsg_UNSET_LOCKCONTINUE();
        aNRG2_change_talk_proc(rcn_guide2, aNRG2_TALK_TALK_END_WAIT);
    }
}

static void aNRG2_job_start_talk_proc(NPC_RCN_GUIDE2_ACTOR* rcn_guide2) {
    mQst_errand_c* errand_p = mQst_GetFirstJobData();
    int talk_proc_idx;

    /* Setup job quest info */
    aNRG2_stepup_job(rcn_guide2, errand_p->base.quest_kind - mQst_ERRAND_FIRSTJOB_CHANGE_CLOTH);
    /* Give the player the necessary item(s) for the job */
    aNRG2_set_possession();

    if (errand_p->base.quest_kind == mQst_ERRAND_FIRSTJOB_INTRODUCTIONS ||
        errand_p->base.quest_kind == mQst_ERRAND_FIRSTJOB_OPEN) {
        talk_proc_idx = aNRG2_TALK_TALK_END_WAIT;
    } else {
        talk_proc_idx = aNRG2_TALK_DEMO_START_WAIT;
    }

    aNRG2_change_talk_proc(rcn_guide2, talk_proc_idx);
    rcn_guide2->next_think_idx = aNRG2_THINK_TALK_START_WAIT;
}

static void aNRG2_job_end_talk_proc(NPC_RCN_GUIDE2_ACTOR* rcn_guide2) {
    static int next_job_no[] = {
        aNRG2_JOB2, aNRG2_JOB3, aNRG2_JOB4, aNRG2_JOB11, aNRG2_JOB6, aNRG2_JOB7,
        aNRG2_JOB7, aNRG2_JOB9, aNRG2_JOB7, aNRG2_JOB3,  aNRG2_JOB5,
    };
    mQst_errand_c* errand_p = mQst_GetFirstJobData();
    int next_job;

    /* If the finished quest was the planting flowers & saplings job & the player hasn't spoken to all villagers &
     * Tortimer, then set the job to introductions.
     */
    if (errand_p->base.quest_kind == mQst_ERRAND_FIRSTJOB_PLANT_FLOWER &&
        (mNpc_CheckFriendAllAnimal(&Now_Private->player_ID) == FALSE || mSC_check_ArbeitPlayer() == FALSE)) {
        next_job = aNRG2_JOB10;
    } else {
        next_job = next_job_no[errand_p->base.quest_kind - mQst_ERRAND_FIRSTJOB_CHANGE_CLOTH];
    }

    aNRG2_setup_job(next_job);
    aNRG2_change_talk_proc(rcn_guide2, aNRG2_TALK_SAY_HELLO);
}

static void aNRG2_3rd_job_end_talk_proc(NPC_RCN_GUIDE2_ACTOR* rcn_guide2) {
    u16 order = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 9);

    /* Hand over the map */
    if (order != 0) {
        aNRG2_job_end_talk_proc(rcn_guide2);

        /* Set params for hand over item */
        mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 1, 2);
        mDemo_Set_OrderValue(mDemo_ORDER_NPC1, 0, ITM_TOWN_MAP);
        mDemo_Set_OrderValue(mDemo_ORDER_NPC1, 1, 7);
        mDemo_Set_OrderValue(mDemo_ORDER_NPC1, 2, 0);

        /* Enable map flag */
        Common_Set(map_flag, TRUE);

        /* Clear demo order */
        mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 9, 0);
    }
}

static void aNRG2_demo2_start_wait_talk_proc(NPC_RCN_GUIDE2_ACTOR* rcn_guide2) {
    u16 order = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 9);

    /* Take quest item back from player */
    if (order != 0) {
        mQst_errand_c* errand_p = mQst_GetFirstJobData();
        int idx = mPr_GetPossessionItemIdxWithCond(Now_Private, errand_p->item, mPr_ITEM_COND_QUEST);

        // This is bad, if you somehow don't have the quest item, the first item in your inventory will be deleted
        if (idx == -1) {
            idx = 0;
        }

        /* Clear item */
        mPr_SetPossessionItem(Now_Private, idx, 0, mPr_ITEM_COND_NORMAL);

        /* Clear demo order */
        mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 9, 0);

        /* Prevent player from continuing dialogue */
        mMsg_SET_LOCKCONTINUE();

        /* Tell the player to play hand over animation */
        mPlib_request_main_give_type1(gamePT, errand_p->item, 7, FALSE, FALSE);

        aNRG2_setup_job(errand_p->base.quest_kind - mQst_ERRAND_FIRSTJOB_CHANGE_CLOTH);
        aNRG2_change_talk_proc(rcn_guide2, aNRG2_TALK_DEMO2_START_WAIT2);
    }
}

static void aNRG2_demo2_start_wait2_talk_proc(NPC_RCN_GUIDE2_ACTOR* rcn_guide2) {
    /* Wait for hand over item request mode */
    if (Common_Get(clip).handOverItem_clip->request_mode == aHOI_REQUEST_TRANS_WAIT) {
        mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 1, 3);
        aNRG2_change_talk_proc(rcn_guide2, aNRG2_TALK_DEMO2_END);
    }
}

static void aNRG2_demo2_end_wait_talk_proc(NPC_RCN_GUIDE2_ACTOR* rcn_guide2) {
    /* Wait for hand over item to finish */
    if (Common_Get(clip).handOverItem_clip->master_actor == NULL) {
        /* Allow player to continue the dialogue now */
        mMsg_UNSET_LOCKCONTINUE();
        aNRG2_job_start_talk_proc(rcn_guide2);
    }
}

static void aNRG2_give_new_paper_talk_proc(NPC_RCN_GUIDE2_ACTOR* rcn_guide2) {
    mMsg_Window_c* msg_p = mMsg_Get_base_window_p();

    if (aNRG2_check_job_start() == TRUE) {
        /* Give another piece of stationery to the player */
        mMsg_Set_continue_msg_num(msg_p, 0x0805); // 'Here! Here's another piece of paper.'
        aNRG2_job_start_talk_proc(rcn_guide2);
        rcn_guide2->can_ask_again_flag = TRUE;
    } else {
        /* Player has full pockets so tell them */
        mMsg_Set_continue_msg_num(msg_p, 0x07FA); // '...What have we here?'
        aNRG2_change_talk_proc(rcn_guide2, aNRG2_TALK_TALK_END_WAIT);
        rcn_guide2->can_ask_again_flag = FALSE;
    }
}

static void aNRG2_check_more_paper_talk_proc(NPC_RCN_GUIDE2_ACTOR* rcn_guide2) {
    u16 order = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 9);
    mQst_errand_c* errand_p;

    if (order != 0) {
        /* Clear the demo order */
        mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 9, 0);

        switch (mChoice_GET_CHOSENUM()) {
            case mChoice_CHOICE0:
                /* Player asked for more paper, so give them some if they have inv space */
                errand_p = mQst_GetFirstJobData();
                aNRG2_give_new_paper_talk_proc(rcn_guide2);
                errand_p->base.progress = 2;
                break;
            case mChoice_CHOICE1:
                /* Player said they don't need more paper */
                aNRG2_change_talk_proc(rcn_guide2, aNRG2_TALK_TALK_END_WAIT);
                rcn_guide2->can_ask_again_flag = FALSE;
                break;
        }
    }
}

static void aNRG2_decide_new_target_talk_proc(NPC_RCN_GUIDE2_ACTOR* rcn_guide2) {
    u16 order = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 9);
    mQst_errand_c* errand_p;

    if (order != 0) {
        errand_p = mQst_GetFirstJobData();

        /* Clear the demo order */
        mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 9, 0);

        aNRG2_setup_job(errand_p->base.quest_kind - mQst_ERRAND_FIRSTJOB_CHANGE_CLOTH);
        aNRG2_stepup_job(rcn_guide2, errand_p->base.quest_kind - mQst_ERRAND_FIRSTJOB_CHANGE_CLOTH);
        aNRG2_change_talk_proc(rcn_guide2, aNRG2_TALK_CHECK_MORE_PAPER);
    }
}

static void aNRG2_demo3_start_wait_talk_proc(NPC_RCN_GUIDE2_ACTOR* rcn_guide2) {
    u16 order = mDemo_Get_OrderValue(mDemo_ORDER_NPC0, 9);
    mQst_errand_c* errand_p;
    int idx;

    if (order != 0) {
        errand_p = mQst_GetFirstJobData();
        idx = mPr_GetPossessionItemIdxWithCond(Now_Private, errand_p->item, mPr_ITEM_COND_QUEST);

        if (idx == -1) {
            /* If the job's tool item can't be found then try the player's equipped item */
            if (Now_Private->equipment == errand_p->item) {
                Now_Private->equipment = EMPTY_NO;
            }
        } else {
            mPr_SetPossessionItem(Now_Private, idx, EMPTY_NO, mPr_ITEM_COND_NORMAL);
        }

        /* Clear the demo order */
        mDemo_Set_OrderValue(mDemo_ORDER_NPC0, 9, 0);

        mMsg_SET_LOCKCONTINUE();
        mPlib_request_main_give_type1(gamePT, errand_p->item, 7, FALSE, FALSE);
        aNRG2_setup_job(aNRG2_JOB8);
        aNRG2_change_talk_proc(rcn_guide2, aNRG2_TALK_DEMO3_START_WAIT2);
    }
}

static void aNRG2_all_job_end_talk_proc(NPC_RCN_GUIDE2_ACTOR* rcn_guide2) {
    rcn_guide2->next_think_idx = aNRG2_THINK_ALL_JOB_END;
    aNRG2_change_talk_proc(rcn_guide2, aNRG2_TALK_TALK_END_WAIT);
}

static void aNRG2_change_talk_proc(NPC_RCN_GUIDE2_ACTOR* rcn_guide2, int talk_proc_idx) {
    // clang-format off
    static aNRG2_TALK_PROC proc[] = {
        &aNRG2_say_hello_talk_proc,
        &aNRG2_say_hello_sp_talk_proc,
        &aNRG2_say_hello_sp2_talk_proc,
        &aNRG2_cloth_chk_talk_proc,
        (aNRG2_TALK_PROC)&none_proc1,
        &aNRG2_demo_start_wait_talk_proc,
        &aNRG2_demo_end_wait_talk_proc,
        &aNRG2_demo_end_wait2_talk_proc,
        &aNRG2_job_start_talk_proc,
        &aNRG2_job_end_talk_proc,
        &aNRG2_3rd_job_end_talk_proc,
        &aNRG2_demo2_start_wait_talk_proc,
        &aNRG2_demo2_start_wait2_talk_proc,
        &aNRG2_demo2_end_wait_talk_proc,
        &aNRG2_give_new_paper_talk_proc,
        &aNRG2_check_more_paper_talk_proc,
        &aNRG2_decide_new_target_talk_proc,
        &aNRG2_demo3_start_wait_talk_proc,
        &aNRG2_demo2_start_wait2_talk_proc,
        &aNRG2_demo2_end_wait_talk_proc,
        &aNRG2_all_job_end_talk_proc,
    };
    // clang-format on

    rcn_guide2->talk_proc = proc[talk_proc_idx];
}

static void aNRG2_set_goods_talk_info(ACTOR* actorx) {
    NPC_RCN_GUIDE2_ACTOR* rcn_guide2 = (NPC_RCN_GUIDE2_ACTOR*)actorx;
    int msg_no = 0x081C;

    /* Check if it's a raffle day */
    if (Common_Get(tanuki_shop_status) == mSP_TANUKI_SHOP_STATUS_FUKUBIKI) {
        msg_no = 0x0833;
    }

    mDemo_Set_msg_num(msg_no);
    mDemo_Set_talk_turn(TRUE);
    rcn_guide2->talk_proc = (aNRG2_TALK_PROC)&none_proc1;
}

static int aNRG2_goods_talk_request(ACTOR* actorx, GAME* game) {
    PLAYER_ACTOR* player = GET_PLAYER_ACTOR_GAME(game);
    int res = FALSE;

    if (player != NULL) {
        int ux;
        int uz;
        mActor_name_t item;

        mFI_Wpos2UtNum(&ux, &uz, player->forward_ut_pos);
        item = Common_Get(clip).shop_design_clip->unitNum2ItemNo_proc(ux, uz);
        if (player->a_btn_pressed == TRUE && item != EXIT_DOOR1 && item != EMPTY_NO && item != RSV_WALL_NO &&
            item != RSV_NO && item != DOOR0) {
            /* Player interacted with shop goods, tell them they're inaccessible currently */
            NPC_RCN_GUIDE2_ACTOR* rcn_guide2 = (NPC_RCN_GUIDE2_ACTOR*)actorx;

            mDemo_Request(mDemo_TYPE_SPEAK, actorx, &aNRG2_set_goods_talk_info);
            rcn_guide2->talk_proc_idx = 0;
            res = TRUE;
        }
    }

    return res;
}

static int aNRG2_cloth_check(void) {
    mQst_errand_c* errand_p = mQst_GetFirstJobData();
    int res = FALSE;

    if (errand_p->base.quest_kind > mQst_ERRAND_FIRSTJOB_CHANGE_CLOTH &&
        errand_p->info.first_job.wrong_cloth == FALSE && Now_Private->cloth.item != ITM_CLOTH016) {
        /* Player changed out of work uniform on the job, now they get a stern talking to! */
        res = TRUE;
    }

    return res;
}

static int aNRG2_check_upstair(void) {
    PLAYER_ACTOR* player = GET_PLAYER_ACTOR_NOW();
    u16 angle_y = player->actor_class.shape_info.rotation.y;
    int res = FALSE;

    if (angle_y > DEG2SHORT_ANGLE2(135.0f) && angle_y < DEG2SHORT_ANGLE2(225.0f) &&
        player->item_in_front == RSV_POLICE_ITEM_0) {
        res = TRUE;
    }

    return res;
}

static void aNRG2_set_force_talk_info(ACTOR* actorx) {
    static aNRG2_talk_info_c dt_tbl[] = {
        { 0x07EE, &aNRG2_say_hello_talk_proc },    /* 'Well, finally you arrive!' */
        { 0x07EF, &aNRG2_say_hello_talk_proc },    /* 'So you're back again today?' */
        { 0x07EE, &aNRG2_say_hello_sp_talk_proc }, /* 'Well, finally you arrive!' (already wearing work uniform) */
        { 0x0832, &aNRG2_cloth_chk_talk_proc },    /* 'Why did you change out of your uniform, hm?' */
        { 0x0834, (aNRG2_TALK_PROC)&none_proc1 },  /* 'Stop right there!' (Going up to 2nd floor) */
    };

    aNRG2_talk_info_c* data;
    NPC_RCN_GUIDE2_ACTOR* rcn_guide2 = (NPC_RCN_GUIDE2_ACTOR*)actorx;
    mQst_errand_c* errand_p = mQst_GetFirstJobData();
    int talk_idx;

    /* Figure out our talk state */
    if (aNRG2_cloth_check() == TRUE) {
        talk_idx = aNRG2_FORCE_TALK_CLOTH_CHK; // Player changed out of their work uniform
        errand_p->info.first_job.wrong_cloth = TRUE;
    } else if (aNRG2_check_upstair() == TRUE) {
        talk_idx = aNRG2_FORCE_TALK_UPSTAIR_CHK; // Player tried going upstairs in Nookington's
    } else {
        talk_idx = rcn_guide2->talk_idx;
    }
    data = &dt_tbl[talk_idx];

    /* If assigning a new job then set the necessary text strings */
    if (mQst_CheckFirstJobFin(errand_p) == FALSE) {
        aNRG2_set_str_proc();
    }

    /* Apply the relevant data */
    mDemo_Set_msg_num(data->msg_no);
    mDemo_Set_talk_turn(TRUE);
    rcn_guide2->talk_proc = data->talk_proc;
}

static void aNRG2_force_talk_request(ACTOR* actorx, GAME* game) {
    NPC_RCN_GUIDE2_ACTOR* rcn_guide2 = (NPC_RCN_GUIDE2_ACTOR*)actorx;

    mDemo_Request(mDemo_TYPE_SPEAK, actorx, &aNRG2_set_force_talk_info);
    rcn_guide2->talk_proc_idx = 0;
}

static void aNRG2_set_norm_talk_info(ACTOR* actorx) {
    // clang-format off
    static aNRG2_talk_info_c dt_tbl[] = {
        { 0x07F1, &aNRG2_job_start_talk_proc },
        { 0x07F6, &aNRG2_job_start_talk_proc },
        { 0x07FB, &aNRG2_job_start_talk_proc },
        { 0x0802, &aNRG2_job_start_talk_proc },
        { 0x080C, &aNRG2_job_start_talk_proc },
        { 0x0830, &aNRG2_job_start_talk_proc },
        { 0x0813, &aNRG2_job_start_talk_proc },
        { 0x0818, &aNRG2_job_start_talk_proc },
        { 0x0821, &aNRG2_job_start_talk_proc },
        { 0x0827, &aNRG2_job_start_talk_proc },
        { 0x07F0, (aNRG2_TALK_PROC)&none_proc1 },
        { 0x07F5, (aNRG2_TALK_PROC)&none_proc1 },
        { 0x07FA, (aNRG2_TALK_PROC)&none_proc1 },
        { 0x07FA, (aNRG2_TALK_PROC)&none_proc1 },
        { 0x07FA, (aNRG2_TALK_PROC)&none_proc1 },
        { 0x0826, (aNRG2_TALK_PROC)&none_proc1 },
        { 0x07FA, (aNRG2_TALK_PROC)&none_proc1 },
        { 0x0818, (aNRG2_TALK_PROC)&none_proc1 },
        { 0x07F3, (aNRG2_TALK_PROC)&none_proc1 },
        { 0x081F, &aNRG2_job_start_talk_proc },
        { 0x0835, (aNRG2_TALK_PROC)&none_proc1 },
        { 0x07F8, (aNRG2_TALK_PROC)&none_proc1 },
        { 0x07FE, (aNRG2_TALK_PROC)&none_proc1 },
        { 0x07FF, &aNRG2_demo2_start_wait_talk_proc },
        { 0x0807, &aNRG2_check_more_paper_talk_proc },
        { 0x0808, &aNRG2_decide_new_target_talk_proc },
        { 0x0804, &aNRG2_give_new_paper_talk_proc },
        { 0x080F, (aNRG2_TALK_PROC)&none_proc1 },
        { 0x0810, &aNRG2_demo2_start_wait_talk_proc },
        { 0x0815, (aNRG2_TALK_PROC)&none_proc1 },
        { 0x0816, &aNRG2_demo3_start_wait_talk_proc },
        { 0x0819, (aNRG2_TALK_PROC)&none_proc1 },
        { 0x0822, (aNRG2_TALK_PROC)&none_proc1 },
        { 0x0829, (aNRG2_TALK_PROC)&none_proc1 },
        { 0x07F4, &aNRG2_job_end_talk_proc },
        { 0x07F9, &aNRG2_job_end_talk_proc },
        { 0x0801, &aNRG2_3rd_job_end_talk_proc },
        { 0x080B, &aNRG2_job_end_talk_proc },
        { 0x0812, &aNRG2_job_end_talk_proc },
        { 0x0818, &aNRG2_job_end_talk_proc },
        { 0x081A, &aNRG2_all_job_end_talk_proc },
        { 0x0828, &aNRG2_job_end_talk_proc },
        { 0x0830, &aNRG2_job_end_talk_proc },
        { 0x0836, (aNRG2_TALK_PROC)&none_proc1 },
    };
    // clang-format on

    NPC_RCN_GUIDE2_ACTOR* rcn_guide2 = (NPC_RCN_GUIDE2_ACTOR*)actorx;
    int talk_idx = rcn_guide2->talk_idx;
    aNRG2_talk_info_c* data = &dt_tbl[talk_idx];
    mQst_errand_c* errand_p = mQst_GetFirstJobData();

    if (talk_idx >= aNRG2_NORM_TALK_J1_CONT1 && talk_idx <= aNRG2_NORM_TALK_J11_CONT1) {
        rcn_guide2->can_ask_again_flag = TRUE;
    }

    if (mQst_CheckFirstJobFin(errand_p) == FALSE) {
        aNRG2_set_str_proc();
    }

    mDemo_Set_msg_num(data->msg_no);
    rcn_guide2->talk_proc = data->talk_proc;
}

static void aNRG2_norm_talk_request(ACTOR* actorx, GAME* game) {
    NPC_RCN_GUIDE2_ACTOR* rcn_guide2 = (NPC_RCN_GUIDE2_ACTOR*)actorx;

    if (aNRG2_goods_talk_request(actorx, game) == FALSE) {
        if (aNRG2_cloth_check() == TRUE) {
            aNRG2_force_talk_request(actorx, game);
        } else if (aNRG2_check_upstair() == TRUE) {
            aNRG2_force_talk_request(actorx, game);
        } else {
            mDemo_Request(mDemo_TYPE_TALK, actorx, &aNRG2_set_norm_talk_info);
            rcn_guide2->talk_proc_idx = 0;
        }
    }
}

static int aNRG2_talk_init(ACTOR* actorx, GAME* game) {
    NPC_RCN_GUIDE2_ACTOR* rcn_guide2 = (NPC_RCN_GUIDE2_ACTOR*)actorx;

    rcn_guide2->npc_class.talk_info.talk_request_proc = (aNPC_TALK_REQUEST_PROC)&none_proc1;
    mDemo_Set_ListenAble();
    return TRUE;
}

static int aNRG2_talk_end_chk(ACTOR* actorx, GAME* game) {
    NPC_RCN_GUIDE2_ACTOR* rcn_guide2 = (NPC_RCN_GUIDE2_ACTOR*)actorx;
    GAME_PLAY* play = (GAME_PLAY*)game;
    int res = FALSE;

    (*rcn_guide2->talk_proc)(rcn_guide2);

    if (mDemo_Check(mDemo_TYPE_SPEAK, actorx) == FALSE && mDemo_Check(mDemo_TYPE_TALK, actorx) == FALSE) {
        aNRG2_setup_think_proc(rcn_guide2, play, rcn_guide2->next_think_idx);
        res = TRUE;
    }

    return res;
}
