#ifndef M_QUEST_H
#define M_QUEST_H

#include "types.h"
#include "libu64/gfxprint.h"
#include "lb_rtc.h"
#include "m_actor_type.h"
#include "m_personal_id.h"
#include "m_npc_personal_id.h"

#ifdef __cplusplus
extern "C" {
#endif

#define mQst_MAX_TIME_LIMIT_DAYS 28
#define mQst_CHECK_NPC_RECEIPIENT 0
#define mQst_CHECK_NPC_SENDER 1

#define mQst_LETTER_RANK_MIN 0
#define mQst_LETTER_RANK_0 mQst_LETTER_RANK_MIN
#define mQst_LETTER_RANK_1 1
#define mQst_LETTER_RANK_2 2
#define mQst_LETTER_RANK_3 3
#define mQst_LETTER_RANK_4 4
#define mQst_LETTER_RANK_5 5
#define mQst_LETTER_RANK_6 6
#define mQst_LETTER_RANK_7 7
#define mQst_LETTER_RANK_8 8
#define mQst_LETTER_RANK_9 9
#define mQst_LETTER_RANK_10 10
#define mQst_LETTER_RANK_11 11
#define mQst_LETTER_RANK_MAX mQst_LETTER_RANK_11 + 1

#define mQst_LETTER_SCORE_BONUS 3   /* Given when the raw score of the letter has passed the threshold */
#define mQst_LETTER_PRESENT_BONUS 6 /* Given when a present is attached */

#define mQst_LETTER_OKAY_LENGTH 17
#define mQst_LETTER_GOOD_LENGTH 49

enum {
    mQst_QUEST_TYPE_DELIVERY, /* Deliver item quest */
    mQst_QUEST_TYPE_ERRAND,   /* Villager 'can I help' quests */
    mQst_QUEST_TYPE_CONTEST,  /* Villager send letter, plant flowers, bring ball, etc */
    mQst_QUEST_TYPE_NONE,

    mQst_QUEST_TYPE_NUM = mQst_QUEST_TYPE_NONE
};

/* sizeof(mQst_base_c) == 0xC */
typedef struct quest_base_s {
    /* 0x00 */ u32 quest_type : 2;         /* type, 0 = delivery, 1 = errand, 2 = contest, 3 = none */
    /* 0x00 */ u32 quest_kind : 6;         /* kind, differs by type */
    /* 0x01 */ u32 time_limit_enabled : 1; /* when set, the time limit will be utilized */
    /* 0x01 */ u32 progress : 4;           /* progress towards quest goal */
    /* 0x01 */ u32 give_reward : 1;        /* player cannot take the item, and will skip quest completion checks */
    /* 0x01 */ u32 unused : 2;

    /* 0x02 */ lbRTC_time_c time_limit;
} mQst_base_c;

/* Contest Quest */

enum {
    mQst_CONTEST_KIND_FRUIT,   /* get fruit for villager */
    mQst_CONTEST_KIND_SOCCER,  /* get ball for villager */
    mQst_CONTEST_KIND_SNOWMAN, /* build snowman for villager */
    mQst_CONTEST_KIND_FLOWER,  /* plant flowers for villager */
    mQst_CONTEST_KIND_FISH,    /* get fish for villager */
    mQst_CONTEST_KIND_INSECT,  /* get insect for villager */
    mQst_CONTEST_KIND_LETTER,  /* send letter to villager */

    mQst_CONTEST_KIND_NUM
};

enum {
    mQst_CONTEST_DATA_NONE,
    mQst_CONTEST_DATA_FLOWER,
    mQst_CONTEST_DATA_LETTER,

    mQst_CONTEST_DATA_NUM
};

/* sizeof(mQst_contest_info_u) == 4 */
typedef union quest_contest_info_s {
    struct {
        /* 0x00 */ u8 flowers_requested; /* number of flowers village requests be planted in acre */
    } flower_data;

    struct {
        /* 0x00 */ u8 score;              /* score rank of letter */
        /* 0x02 */ mActor_name_t present; /* present sent with letter */
    } letter_data;
} mQst_contest_info_u;

/* sizeof(mQst_contest_c) == 0x28 */
typedef struct quest_contest_s {
    /* 0x00 */ mQst_base_c base;             /* quest base struct */
    /* 0x0C */ mActor_name_t requested_item; /* item (if any) requested by the villager */
    /* 0x0E */ PersonalID_c player_id;       /* personal id of the player */
    /* 0x22 */ s8 type;                      /* type of quest, seems to be repeat of data in quest base */
    /* 0x24 */ mQst_contest_info_u info;     /* contest info for flower & letter quests */
} mQst_contest_c;

/* Delivery Quest */

enum {
    mQst_DELIVERY_KIND_NORMAL,  // standard delivery
    mQst_DELIVERY_KIND_FOREIGN, // delivered to a foreign animal
    mQst_DELIVERY_KIND_REMOVE,  // delivered to the animal who last left for another town
    mQst_DELIVERY_KIND_LOST,    // assumed, probably for when a delivery is 'undeliverable'

    mQst_DELIVERY_KIND_NUM
};

/* sizeof(mQst_delivery_c) == 0x28 */
typedef struct quest_delivery_s {
    /* 0x00 */ mQst_base_c base;          /* quest base info */
    /* 0x0C */ AnmPersonalID_c recipient; /* villager who will receive it */
    /* 0x1A */ AnmPersonalID_c sender;    /* villager who sent it */
} mQst_delivery_c;

/* Errand Quest */
#define mQst_ERRAND_FIRST_JOB_ANIMAL_NUM 2
#define mQst_ERRAND_CHAIN_ANIMAL_NUM 3

enum {
    mQst_ERRAND_REQUEST,
    mQst_ERRAND_REQUEST_CONTINUE,
    mQst_ERRAND_REQUEST_FINAL,

    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,
    mQst_ERRAND_FIRSTJOB_START,

    mQst_ERRAND_NUM
};

enum {
    mQst_ERRAND_TYPE_NONE,
    mQst_ERRAND_TYPE_CHAIN,
    mQst_ERRAND_TYPE_FIRST_JOB,

    mQst_ERRAND_TYPE_NUM
};

/* sizeof(mQst_first_job_c) == 0x20 */
typedef struct quest_first_job_s {
    /* 0x00 */ AnmPersonalID_c used_ids[mQst_ERRAND_FIRST_JOB_ANIMAL_NUM]; /* villagers already used for first job quest
                                                                              (furniture, then letter) */
    /* 0x1C */ u8 used_num : 7;                                            /* used count for 'used_ids' */
    /* 0x1C */ u8 wrong_cloth : 1; /* set to TRUE if player changes out of work uniform during chores */
} mQst_firstjob_c;

/* sizeof(mQst_errand_chain_c) == 0x2C */
typedef struct quest_errand_chain_s {
    /* 0x00 */ AnmPersonalID_c used_ids[mQst_ERRAND_CHAIN_ANIMAL_NUM];
    /* 0x2A */ u8 used_num;
} mQst_errand_chain_c;

/* sizeof(mQst_errand_info_u) == 0x2C */
typedef union {
    mQst_errand_chain_c chain;
    mQst_firstjob_c first_job;
} mQst_errand_info_u;

/* sizeof(mQst_errand_c) == 0x58 */
typedef struct quest_errand_s {
    /* 0x00 */ mQst_base_c base;          /* quest base info */
    /* 0x0C */ AnmPersonalID_c recipient; /* villager who will receive it */
    /* 0x1A */ AnmPersonalID_c sender;    /* villager who sent it */
    /* 0x28 */ mActor_name_t item;        /* errand item */
    /* 0x2A */ s8 pockets_idx : 5;        /* index in player pockets where the errand item is */
    /* 0x2A */ s8 errand_type : 3;        /* errand type */
    /* 0x2C */ mQst_errand_info_u info;   /* errand type-specific data */
} mQst_errand_c;

/* 'Not Saved' Quest */
typedef struct not_saved_quest_s {
    int work;
    u8 h;
} mQst_not_saved_c;

extern void mQst_ClearQuestInfo(mQst_base_c* quest);
extern void mQst_ClearDelivery(mQst_delivery_c* delivery, int num);
extern void mQst_ClearErrand(mQst_errand_c* errand, int num);
extern void mQst_ClearContest(mQst_contest_c* contest);
extern void mQst_ClearNotSaveQuest(mQst_not_saved_c* not_saved);
extern void mQst_CopyQuestInfo(mQst_base_c* dst, mQst_base_c* src);
extern void mQst_CopyDelivery(mQst_delivery_c* dst, mQst_delivery_c* src);
extern void mQst_CopyErrand(mQst_errand_c* dst, mQst_errand_c* src);
extern int mQst_CheckFreeQuest(mQst_base_c* quest);
extern int mQst_CheckLimitOver(mQst_base_c* quest);
extern int mQst_GetOccuredDeliveryIdx(int delivery_kind);
extern int mQst_ClearQuestbyPossessionIdx(int idx);
extern int mQst_CheckLimitbyPossessionIdx(int idx);
extern void mQst_ClearGrabItemInfo();
extern void mQst_CheckGrabItem(mActor_name_t item, int pocket_idx);
extern void mQst_CheckPutItem(mActor_name_t item, int pocket_idx);
extern int mQst_CheckNpcExistbyItemIdx(int idx, int sender_or_receipient);
extern int mQst_GetToFromName(u8* to_name, u8* from_name, int idx);
extern int mQst_GetOccuredContestIdx(int kind);
extern int mQst_GetFlowerSeedNum(int block_x, int block_z);
extern int mQst_GetFlowerNum(int block_x, int block_z);
extern int mQst_GetNullNoNum(int block_x, int block_z);
extern void mQst_SetItemNameStr(mActor_name_t item, int string_no);
extern void mQst_SetItemNameFreeStr(mActor_name_t item, int string_no);
extern int mQst_SendRemail(mQst_contest_c* contest, AnmPersonalID_c* sender_id);
extern void mQst_SetReceiveLetter(mQst_contest_c* contest, PersonalID_c* sender_id, u8* body, mActor_name_t present);
extern mQst_errand_c* mQst_GetFirstJobData();
extern int mQst_CheckFirstJobQuestbyItemIdx(int idx);
extern int mQst_CheckFirstJobFin(mQst_errand_c* errand);
extern int mQst_CheckRemoveTarget(mQst_errand_c* errand);
extern void mQst_SetFirstJobStart(mQst_errand_c* errand);
extern void mQst_SetFirstJobChangeCloth(mQst_errand_c* errand, mActor_name_t item);
extern void mQst_SetFirstJobSeed(mQst_errand_c* errand);
extern void mQst_SetFirstJobHello(mQst_errand_c* errand);
extern void mQst_SetFirstJobFurniture(mQst_errand_c* errand, AnmPersonalID_c* pid, mActor_name_t item, int slot);
extern void mQst_SetFirstJobLetter(mQst_errand_c* errand, AnmPersonalID_c* pid);
extern void mQst_SetFirstJobLetter2(mQst_errand_c* errand, AnmPersonalID_c* pid);
extern void mQst_SetFirstJobOpenQuest(mQst_errand_c* errand);
extern void mQst_SetFirstJobCarpet(mQst_errand_c* errand, AnmPersonalID_c* pid, mActor_name_t item, int slot);
extern void mQst_SetFirstJobAxe(mQst_errand_c* errand, AnmPersonalID_c* pid, mActor_name_t item, int slot);
extern void mQst_SetFirstJobAxe2(mQst_errand_c* errand, AnmPersonalID_c* pid, mActor_name_t item, int slot);
extern void mQst_SetFirstJobNotice(mQst_errand_c* errand);
extern int mQst_GetRandom(int max);
extern void mQst_GetGoods_common(mActor_name_t* item, AnmPersonalID_c* pid, int category, mActor_name_t* exist_table,
                                 int exist_num, int list);
extern int mQst_CheckSoccerTarget(ACTOR* actor);
extern void mQst_NextSoccer(ACTOR* actor);
extern void mQst_NextSnowman(xyz_t snowman_pos);
extern void mQst_BackSnowman(xyz_t snowman_pos);
extern void mQst_PrintQuestInfo(gfxprint_t* gfxprint);

#ifdef __cplusplus
}
#endif

#endif
