static void aEGH_look_player(EV_GHOST_ACTOR* ghost, GAME_PLAY* play) {
    if (ghost->npc_class.action.step == aNPC_ACTION_END_STEP) {
        u8 action = 4;
        s16 player_y = ghost->npc_class.actor_class.player_angle_y;
        s16 rot_y = ghost->npc_class.actor_class.shape_info.rotation.y;
        s16 diff = player_y - rot_y;

        if (ABS(diff) < DEG2SHORT_ANGLE(67.5f)) {
            action = 0;
        }

        aEGH_set_request_act(ghost, 4, action, 2, 1, 0, 0);
    }
}

static int aEGH_bitset_func(u16 bit) {
    u32 player_no = Common_Get(player_no);
    mEv_gst_c* ghost_save = (mEv_gst_c*)mEv_get_save_area(mEv_EVENT_GHOST, 54);
    mEv_gst_common_c* ghost_common = (mEv_gst_common_c*)mEv_get_common_area(mEv_EVENT_GHOST, 55);

    if (player_no == mPr_FOREIGNER) {
        if (ghost_common != NULL) {
            ghost_common->flags |= bit;
            return TRUE;
        }
    } else if (ghost_save != NULL) {
        ghost_save->flags |= (u16)(bit << player_no);
        return TRUE;
    }

    return FALSE;
}

static int aEGH_bitclr_func(u16 bit) {
    u32 player_no = Common_Get(player_no);
    mEv_gst_c* ghost_save = (mEv_gst_c*)mEv_get_save_area(mEv_EVENT_GHOST, 54);
    mEv_gst_common_c* ghost_common = (mEv_gst_common_c*)mEv_get_common_area(mEv_EVENT_GHOST, 55);

    if (player_no == mPr_FOREIGNER) {
        if (ghost_common != NULL) {
            ghost_common->flags &= ~bit;
            return TRUE;
        }
    } else if (ghost_save != NULL) {
        ghost_save->flags &= ~(u16)(bit << player_no);
        return TRUE;
    }

    return FALSE;
}

static u16 aEGH_bitcheck_func(u16 bit) {
    u32 player_no = Common_Get(player_no);
    mEv_gst_c* ghost_save = (mEv_gst_c*)mEv_get_save_area(mEv_EVENT_GHOST, 54);
    mEv_gst_common_c* ghost_common = (mEv_gst_common_c*)mEv_get_common_area(mEv_EVENT_GHOST, 55);

    if (player_no == mPr_FOREIGNER) {
        if (ghost_common != NULL) {
            return ghost_common->flags & bit;
        }
    } else if (ghost_save != NULL) {
        return (u16)(bit << player_no) & ghost_save->flags;
    }

    return FALSE;
}

static int aEGH_equal_block(EV_GHOST_ACTOR* ghost, GAME_PLAY* play) {
    int bx;
    int bz;

    mFI_Wpos2BlockNum(&bx, &bz, GET_PLAYER_ACTOR(play)->actor_class.world.position);
    return bx == ghost->npc_class.actor_class.block_x && bz == ghost->npc_class.actor_class.block_z;
}

static int aEGH_time_over() {
    return Common_Get(time.now_sec) > (4 * mTM_SECONDS_IN_HOUR);
}

static void aEGH_byebye_check(EV_GHOST_ACTOR* ghost, GAME_PLAY* play) {
    ACTOR* actorx = (ACTOR*)ghost;

    if (mDemo_Check(mDemo_TYPE_TALK, actorx) == FALSE && mDemo_Check(mDemo_TYPE_SPEAK, actorx) == FALSE &&
        aEGH_time_over() != FALSE) {
        if (aEGH_equal_block(ghost, play)) {
            switch (ghost->think_act) {
                case aEGH_THINK_SPEAK: {
                    aEGH_setup_think_proc(ghost, play, aEGH_THINK_BYEBYE);
                    ghost->msg_no = 0x2EDD;
                    ghost->npc_class.actor_class.talk_distance = 1000.0f;
                    ghost->_9AA = 1;
                    break;
                }

                case aEGH_THINK_NORMAL_WAIT:
                case aEGH_THINK_IRAI_AF:
                case aEGH_THINK_BYE:
                case aEGH_THINK_WELCOM: {
                    Actor_delete((ACTOR*)ghost);
                    break;
                }
            }
        } else {
            aEGH_setup_think_proc(ghost, play, aEGH_THINK_IRAI);
        }
    }
}

static void aEGH_irai(EV_GHOST_ACTOR* ghost, GAME_PLAY* play) {
    if (ghost->npc_class.actor_class.player_distance_xz > 220.0f) {
        aEGH_setup_think_proc(ghost, play, aEGH_THINK_BYE);
    }
}

static void aEGH_bye(EV_GHOST_ACTOR* ghost, GAME_PLAY* play) {
    if (ghost->npc_class.actor_class.player_distance_xz < 200.0f) {
        aEGH_setup_think_proc(ghost, play, aEGH_THINK_WELCOM);
    }
}

static void aEGH_byebye(EV_GHOST_ACTOR* ghost, GAME_PLAY* play) {
    if (ghost->alpha == 0) {
        Actor_delete((ACTOR*)ghost);
    } else {
        if (ghost->bye_bye_timer != 0) {
            ghost->bye_bye_timer--;

            if (ghost->bye_bye_timer == 0) {
                sAdo_SysTrgStart(0x16C);
            }
        } else {
            if (ghost->bye_bye_angle < 30000) {
                ghost->bye_bye_angle += 60;
            }

            ghost->npc_class.actor_class.shape_info.rotation.y += ghost->bye_bye_angle;
            ghost->npc_class.actor_class.world.angle.y = ghost->npc_class.actor_class.shape_info.rotation.y;
            ghost->npc_class.movement.mv_angl = ghost->npc_class.actor_class.world.angle.y;
            ghost->npc_class.movement.mv_add_angl = 0;
        }

        if (ghost->bye_bye_scale_timer != 0) {
            ghost->bye_bye_scale_timer--;
        } else {
            ghost->npc_class.actor_class.scale.x += -0.00004f;
            ghost->npc_class.actor_class.scale.z = ghost->npc_class.actor_class.scale.x;
        }
    }
}

static void aEGH_speak_byebye(EV_GHOST_ACTOR* ghost, GAME_PLAY* play) {
    ACTOR* actorx = (ACTOR*)ghost;

    if (mDemo_Check(mDemo_TYPE_TALK, actorx) == FALSE && mDemo_Check(mDemo_TYPE_SPEAK, actorx) == FALSE &&
        aEGH_equal_block(ghost, play) == FALSE) {
        aEGH_setup_think_proc(ghost, play, aEGH_THINK_IRAI);
    }
}

static void aEGH_think_main_proc(NPC_ACTOR* actorx, GAME_PLAY* play) {
    EV_GHOST_ACTOR* ghost = (EV_GHOST_ACTOR*)actorx;

    (*ghost->think_proc)(ghost, play);
    aEGH_look_player(ghost, play);
}

static void aEGH_think_init_proc(NPC_ACTOR* actorx, GAME_PLAY* play) {
    EV_GHOST_ACTOR* ghost = (EV_GHOST_ACTOR*)actorx;
    u8 think_act;

    if (ghost->_9AC) {
        ghost->_9AC = FALSE;
    } else {
        if (aEGH_bitcheck_func(aEGH_BIT_FOUND_GHOST)) {
            ghost->alpha = 140;
            think_act = aEGH_THINK_SPEAK;
        } else {
            ghost->alpha = 0;
            think_act = aEGH_THINK_IRAI_AF;
        }

        actorx->actor_class.status_data.weight = 255;
        actorx->condition_info.hide_request = FALSE;
        aEGH_setup_think_proc(ghost, play, think_act);
        actorx->condition_info.demo_flg = aNPC_COND_DEMO_SKIP_FOOTSTEPS_VFX | aNPC_COND_DEMO_SKIP_FEEL_CHECK |
                                          aNPC_COND_DEMO_SKIP_FOOTSTEPS | aNPC_COND_DEMO_SKIP_ENTRANCE_CHECK |
                                          aNPC_COND_DEMO_SKIP_HEAD_LOOKAT;
    }
}

static void aEGH_normal_wait_init(EV_GHOST_ACTOR* ghost, GAME_PLAY* play) {
    (*Common_Get(clip).npc_clip->animation_init_proc)((ACTOR*)ghost, aNPC_ANIM_GSTWAIT1, FALSE);
    ghost->npc_class.draw.main_animation.keyframe.frame_control.mode = cKF_FRAMECONTROL_REPEAT;
    ghost->npc_class.action.idx = 0;
    aEGH_set_request_act(ghost, 4, 0, 0, 0, 0, 0);
}

static void aEGH_irai_init(EV_GHOST_ACTOR* ghost, GAME_PLAY* play) {
    ghost->npc_class.actor_class.talk_distance = 80.0f;
    aEGH_normal_wait_init(ghost, play);
    ghost->msg_no = 0x2EE2;
}

static void aEGH_irai_af_init(EV_GHOST_ACTOR* ghost, GAME_PLAY* play) {
    ghost->npc_class.actor_class.talk_distance = 55.0f;
    ghost->msg_no = 0x2EE7;
    (*Common_Get(clip).npc_clip->chg_schedule_proc)((NPC_ACTOR*)ghost, play, 5);
    ghost->npc_class.actor_class.status_data.weight = 80;
}

static void aEGH_bye_init(EV_GHOST_ACTOR* ghost, GAME_PLAY* play) {
    ghost->npc_class.actor_class.talk_distance = 280.0f;
    aEGH_normal_wait_init(ghost, play);
    ghost->msg_no = 0x2ED8;
}

static void aEGH_welcom_init(EV_GHOST_ACTOR* ghost, GAME_PLAY* play) {
    ghost->npc_class.actor_class.talk_distance = 200.0f;
    aEGH_normal_wait_init(ghost, play);
    ghost->msg_no = 0x2ED3;
}

static void aEGH_byebye_init(EV_GHOST_ACTOR* ghost, GAME_PLAY* play) {
    aEGH_bitclr_func(aEGH_BIT_FOUND_GHOST);
    ghost->bye_bye_angle = -1000;
    ghost->bye_bye_timer = 25;
    ghost->bye_bye_scale_timer = 48;
    ghost->bye_bye_transparency_delay_timer = 43;
    aEGH_normal_wait_init(ghost, play);
    ghost->npc_class.head.lock_flag = TRUE;
}

static aEGH_setup_c dt_tbl[aEGH_THINK_NUM] = {
    { aEGH_THINK_PROC_BYE, aEGH_THINK_INIT_NORMAL_WAIT, aEGH_TALK_REQUEST_NONE, aEGH_TALK_END_WAIT,
      aEGH_THINK_NORMAL_WAIT },
    { aEGH_THINK_PROC_BYEBYE, aEGH_THINK_INIT_BYEBYE, aEGH_TALK_REQUEST_NONE, aEGH_TALK_END_WAIT, aEGH_THINK_IRAI },

    { aEGH_THINK_PROC_NONE, aEGH_THINK_INIT_WELCOM, aEGH_TALK_REQUEST_FORCE, aEGH_TALK_END_WAIT, aEGH_THINK_WELCOM },

    { aEGH_THINK_PROC_BYE, aEGH_THINK_INIT_BYE, aEGH_TALK_REQUEST_FORCE, aEGH_TALK_GIVE_ME_WAIT,
      aEGH_THINK_NORMAL_WAIT },

    { aEGH_THINK_PROC_IRAI, aEGH_THINK_INIT_IRAI, aEGH_TALK_REQUEST_FORCE, aEGH_TALK_SELECT_WAIT, aEGH_THINK_SPEAK },

    { aEGH_THINK_PROC_SPEAK_BYEBYE, aEGH_THINK_INIT_NORMAL_WAIT, aEGH_TALK_REQUEST_FORCE, aEGH_TALK_SELECT_ROOF,
      aEGH_THINK_IRAI },

    { aEGH_THINK_PROC_NONE, aEGH_THINK_INIT_IRAI_AF, aEGH_TALK_REQUEST_NORM, aEGH_TALK_END_WAIT, aEGH_THINK_SPEAK }
};

static aEGH_PROC proc_table[aEGH_THINK_PROC_NUM] = { (aEGH_PROC)&none_proc1, &aEGH_irai, &aEGH_bye, &aEGH_byebye,
                                                     &aEGH_speak_byebye };

static aEGH_PROC init_table[aEGH_THINK_INIT_NUM] = { (aEGH_PROC)&none_proc1, &aEGH_normal_wait_init, &aEGH_irai_init,
                                                     &aEGH_irai_af_init,     &aEGH_bye_init,         &aEGH_welcom_init,
                                                     &aEGH_byebye_init };

static void aEGH_setup_think_proc(EV_GHOST_ACTOR* ghost, GAME_PLAY* play, u8 think_act) {
    static aNPC_TALK_REQUEST_PROC talk_request_table[aEGH_TALK_REQUEST_NUM] = { (aNPC_TALK_REQUEST_PROC)&none_proc1,
                                                                                &aEGH_norm_talk_request,
                                                                                &aEGH_force_talk_request };

    aEGH_setup_c* data = &dt_tbl[think_act];

    ghost->think_act = think_act;
    ghost->think_proc = proc_table[data->think_proc];
    ghost->npc_class.talk_info.talk_request_proc = talk_request_table[data->talk_request_proc];
    ghost->talk_act = data->talk_act;
    ghost->after_talk_think_act = data->talk_after_act;
    (*init_table[data->think_init_proc])(ghost, play);
    ghost->_9A7 = TRUE;
}

static void aEGH_think_proc(NPC_ACTOR* actorx, GAME_PLAY* play, int think_type) {
    switch (think_type) {
        case 0:
            aEGH_think_init_proc(actorx, play);
            break;
        case 1:
            aEGH_think_main_proc(actorx, play);
            break;
    }
}

static void aEGH_schedule_init_proc(NPC_ACTOR* actorx, GAME_PLAY* play) {
    actorx->think.think_proc = &aEGH_think_proc;
    (*Common_Get(clip).npc_clip->think_proc)(actorx, play, aNPC_THINK_SPECIAL, 0);
}

static void aEGH_schedule_main_proc(NPC_ACTOR* actorx, GAME_PLAY* play) {
    if ((*Common_Get(clip).npc_clip->think_proc)(actorx, play, -1, 1) == FALSE) {
        (*Common_Get(clip).npc_clip->think_proc)(actorx, play, -1, 2);
    }
}

static void aEGH_schedule_proc(NPC_ACTOR* actorx, GAME_PLAY* play, int sched_type) {
    switch (sched_type) {
        case 0:
            aEGH_schedule_init_proc(actorx, play);
            break;
        case 1:
            aEGH_schedule_main_proc(actorx, play);
            break;
    }
}
