mirror of
https://github.com/ACreTeam/ac-decomp
synced 2026-05-23 06:34:18 -04:00
1127 lines
30 KiB
C
1127 lines
30 KiB
C
#include "m_quest.h"
|
|
|
|
#include "libultra/libultra.h"
|
|
#include "m_name_table.h"
|
|
#include "m_npc.h"
|
|
#include "m_private.h"
|
|
#include "m_item_name.h"
|
|
#include "m_msg.h"
|
|
#include "m_shop.h"
|
|
#include "m_handbill.h"
|
|
#include "m_house.h"
|
|
#include "m_event.h"
|
|
#include "m_common_data.h"
|
|
|
|
typedef struct grab_s {
|
|
mActor_name_t item;
|
|
int pocket_idx;
|
|
int type;
|
|
mQst_delivery_c delivery;
|
|
} mQst_grab_c;
|
|
|
|
static lbRTC_day_t l_delivery_limit[4] = {
|
|
2,
|
|
2,
|
|
2,
|
|
2
|
|
};
|
|
|
|
static lbRTC_day_t l_errand_limit[mQst_ERRAND_NUM] = {
|
|
2,
|
|
2,
|
|
2,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0
|
|
};
|
|
|
|
static lbRTC_day_t l_contest_limit[mQst_CONTEST_KIND_NUM] = {
|
|
1, // mQst_CONTEST_KIND_FRUIT
|
|
1, // mQst_CONTEST_KIND_SOCCER
|
|
1, // mQst_CONTEST_KIND_SNOWMAN
|
|
3, // mQst_CONTEST_KIND_FLOWER
|
|
3, // mQst_CONTEST_KIND_FISH
|
|
3, // mQst_CONTEST_KIND_INSECT
|
|
2 // mQst_CONTEST_KIND_LETTER
|
|
};
|
|
|
|
static lbRTC_day_t l_contest_fin_limit[mQst_CONTEST_KIND_NUM] = {
|
|
3, // mQst_CONTEST_KIND_FRUIT
|
|
3, // mQst_CONTEST_KIND_SOCCER
|
|
3, // mQst_CONTEST_KIND_SNOWMAN
|
|
3, // mQst_CONTEST_KIND_FLOWER
|
|
3, // mQst_CONTEST_KIND_FISH
|
|
3, // mQst_CONTEST_KIND_INSECT
|
|
2 // mQst_CONTEST_KIND_LETTER
|
|
};
|
|
|
|
static lbRTC_day_t* l_limit_table[mQst_QUEST_TYPE_NUM] = {
|
|
l_delivery_limit,
|
|
l_errand_limit,
|
|
l_contest_limit
|
|
};
|
|
|
|
static int l_limit_table_max[mQst_QUEST_TYPE_NUM] = {
|
|
4, // mQst_QUEST_TYPE_DELIVERY
|
|
15, // mQst_QUEST_TYPE_ERRAND
|
|
mQst_CONTEST_KIND_NUM // mQst_QUEST_TYPE_CONTEST
|
|
};
|
|
|
|
extern void mQst_ClearQuestInfo(mQst_base_c* quest) {
|
|
bzero(quest, sizeof(mQst_base_c));
|
|
quest->quest_type = mQst_QUEST_TYPE_NONE;
|
|
}
|
|
|
|
extern void mQst_ClearDelivery(mQst_delivery_c* delivery, int num) {
|
|
int i;
|
|
|
|
for (i = 0; i < num; i++) {
|
|
mQst_ClearQuestInfo(&delivery->base);
|
|
mNpc_ClearAnimalPersonalID(&delivery->recipient);
|
|
mNpc_ClearAnimalPersonalID(&delivery->sender);
|
|
|
|
delivery++;
|
|
}
|
|
}
|
|
|
|
extern void mQst_ClearErrand(mQst_errand_c* errand, int num) {
|
|
int i;
|
|
|
|
for (i = 0; i < num; i++) {
|
|
mQst_ClearQuestInfo(&errand->base);
|
|
mNpc_ClearAnimalPersonalID(&errand->recipient);
|
|
mNpc_ClearAnimalPersonalID(&errand->sender);
|
|
|
|
errand->item = EMPTY_NO;
|
|
errand->pockets_idx = -1;
|
|
errand->errand_type = mQst_ERRAND_TYPE_NONE;
|
|
|
|
bzero(&errand->info, sizeof(mQst_errand_info_u));
|
|
|
|
errand++;
|
|
}
|
|
}
|
|
|
|
extern void mQst_ClearContest(mQst_contest_c* contest) {
|
|
mQst_ClearQuestInfo(&contest->base);
|
|
contest->requested_item = EMPTY_NO;
|
|
mPr_ClearPersonalID(&contest->player_id);
|
|
contest->type = mQst_QUEST_TYPE_NONE;
|
|
bzero(&contest->info, sizeof(mQst_contest_info_u));
|
|
}
|
|
|
|
extern void mQst_ClearNotSaveQuest(mQst_not_saved_c* not_saved) {
|
|
bzero(not_saved, sizeof(mQst_not_saved_c));
|
|
}
|
|
|
|
extern void mQst_CopyQuestInfo(mQst_base_c* dst, mQst_base_c* src) {
|
|
dst->quest_type = src->quest_type;
|
|
dst->quest_kind = src->quest_kind;
|
|
dst->time_limit_enabled = src->time_limit_enabled;
|
|
dst->progress = src->progress;
|
|
dst->give_reward = src->give_reward;
|
|
|
|
lbRTC_TimeCopy(&dst->time_limit, &src->time_limit);
|
|
}
|
|
|
|
extern void mQst_CopyDelivery(mQst_delivery_c* dst, mQst_delivery_c* src) {
|
|
mQst_CopyQuestInfo(&dst->base, &src->base);
|
|
mNpc_CopyAnimalPersonalID(&dst->recipient, &src->recipient);
|
|
mNpc_CopyAnimalPersonalID(&dst->sender, &src->sender);
|
|
}
|
|
|
|
extern void mQst_CopyErrand(mQst_errand_c* dst, mQst_errand_c* src) {
|
|
u8* info_src_p = (u8*)&src->info;
|
|
u8* info_dst_p = (u8*)&dst->info;
|
|
int i;
|
|
|
|
mQst_CopyQuestInfo(&dst->base, &src->base);
|
|
mNpc_CopyAnimalPersonalID(&dst->recipient, &src->recipient);
|
|
mNpc_CopyAnimalPersonalID(&dst->sender, &src->sender);
|
|
dst->item = src->item;
|
|
dst->pockets_idx = src->pockets_idx;
|
|
dst->errand_type = src->errand_type;
|
|
//dst->info = src->info;
|
|
|
|
/* what the fuck guys */
|
|
for (i = 0; i < sizeof(mQst_errand_info_u); i++) {
|
|
*info_dst_p = *info_src_p;
|
|
info_dst_p++;
|
|
info_src_p++;
|
|
}
|
|
}
|
|
|
|
extern int mQst_CheckFreeQuest(mQst_base_c* quest) {
|
|
int res = FALSE;
|
|
if (quest->quest_type == mQst_QUEST_TYPE_NONE) {
|
|
res = TRUE;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
extern int mQst_CheckLimitOver(mQst_base_c* quest) {
|
|
lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time);
|
|
lbRTC_time_c temp;
|
|
int res = FALSE;
|
|
|
|
if (quest->time_limit_enabled == TRUE) {
|
|
if (lbRTC_IsOverTime(&quest->time_limit, rtc_time) == lbRTC_OVER) {
|
|
res = TRUE;
|
|
}
|
|
else if (quest->quest_type < mQst_QUEST_TYPE_NONE) {
|
|
if (lbRTC_GetIntervalDays(&quest->time_limit, rtc_time) >= mQst_MAX_TIME_LIMIT_DAYS) {
|
|
res = TRUE;
|
|
}
|
|
else {
|
|
int type = quest->quest_type;
|
|
u32 kind = quest->quest_kind;
|
|
|
|
if ((u32)quest->quest_kind < l_limit_table_max[type]) {
|
|
int days = l_limit_table[type][quest->quest_kind];
|
|
|
|
if (type == mQst_QUEST_TYPE_CONTEST && quest->progress == 0) {
|
|
days += l_contest_fin_limit[kind];
|
|
}
|
|
|
|
lbRTC_TimeCopy(&temp, &quest->time_limit);
|
|
lbRTC_Sub_DD(&temp, days);
|
|
|
|
if (lbRTC_IsOverTime(rtc_time, &temp) == lbRTC_OVER) {
|
|
res = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
extern int mQst_GetOccuredDeliveryIdx(int delivery_kind) {
|
|
int idx = -1;
|
|
int i;
|
|
mQst_delivery_c* delivery = Common_Get(now_private)->deliveries;
|
|
|
|
for (i = 0; i < mPr_DELIVERY_QUEST_NUM; i++) {
|
|
if (mQst_CheckFreeQuest(&delivery->base) == FALSE && delivery->base.quest_type == mQst_QUEST_TYPE_DELIVERY && (u32)delivery->base.quest_kind == delivery_kind) {
|
|
idx = i;
|
|
break;
|
|
}
|
|
|
|
delivery++;
|
|
}
|
|
|
|
return idx;
|
|
}
|
|
|
|
static int mQst_GetDeliveryIdxbyItemIdx(int idx) {
|
|
int d_idx = -1;
|
|
|
|
if (idx >= 0 && idx < mPr_POCKETS_SLOT_COUNT && mQst_CheckFreeQuest(&Common_Get(now_private)->deliveries[idx].base) == FALSE) {
|
|
d_idx = idx;
|
|
}
|
|
|
|
return d_idx;
|
|
}
|
|
|
|
static int mQst_GetErrandIdxbyItemIdx(int idx) {
|
|
int d_idx = -1;
|
|
int i;
|
|
mQst_errand_c* errand;
|
|
mActor_name_t item;
|
|
|
|
if (idx >= 0 && idx < mPr_POCKETS_SLOT_COUNT) {
|
|
Private_c* priv = Common_Get(now_private);
|
|
|
|
if (mPr_GET_ITEM_COND(priv->inventory.item_conditions, idx) == mPr_ITEM_COND_QUEST) {
|
|
errand = priv->errands;
|
|
item = priv->inventory.pockets[idx];
|
|
|
|
for (i = 0; i < mPr_ERRAND_QUEST_NUM; i++) {
|
|
if (mQst_CheckFreeQuest(&errand->base) == FALSE && errand->pockets_idx == idx && errand->item == item) {
|
|
d_idx = i;
|
|
break;
|
|
}
|
|
|
|
errand++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return d_idx;
|
|
}
|
|
|
|
extern int mQst_ClearQuestbyPossessionIdx(int idx) {
|
|
int res = FALSE;
|
|
|
|
if (idx >= 0 && idx < mPr_POCKETS_SLOT_COUNT) {
|
|
if (mQst_GetDeliveryIdxbyItemIdx(idx) != -1) {
|
|
mQst_ClearDelivery(Common_Get(now_private)->deliveries + idx, 1);
|
|
res = TRUE;
|
|
}
|
|
else {
|
|
int errand_idx = mQst_GetErrandIdxbyItemIdx(idx);
|
|
|
|
if (errand_idx != -1) {
|
|
mQst_ClearErrand(Common_Get(now_private)->errands + errand_idx, 1);
|
|
res = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
extern int mQst_CheckLimitbyPossessionIdx(int idx) {
|
|
int res = FALSE;
|
|
|
|
if (idx >= 0 && idx < mPr_POCKETS_SLOT_COUNT) {
|
|
mQst_delivery_c* delivery = Common_Get(now_private)->deliveries + idx;
|
|
mQst_errand_c* errand = Common_Get(now_private)->errands;
|
|
mActor_name_t item = Common_Get(now_private)->inventory.pockets[idx];
|
|
|
|
if (item != EMPTY_NO) {
|
|
if (mQst_CheckFreeQuest(&delivery->base) == FALSE && mQst_CheckLimitOver(&delivery->base) == TRUE) {
|
|
res = TRUE;
|
|
}
|
|
|
|
if (res == FALSE) {
|
|
int i;
|
|
|
|
for (i = 0; i < mPr_ERRAND_QUEST_NUM; i++) {
|
|
if (mQst_CheckFreeQuest(&errand->base) == FALSE && errand->pockets_idx == idx && item == errand->item && mQst_CheckLimitOver(&errand->base) == TRUE) {
|
|
res = TRUE;
|
|
break;
|
|
}
|
|
|
|
errand++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
static mQst_grab_c l_mqst_grab;
|
|
|
|
static void mQst_ClearGrabItemInfo_common(mQst_grab_c* grab) {
|
|
grab->item = RSV_NO;
|
|
grab->pocket_idx = -1;
|
|
grab->type = mQst_QUEST_TYPE_NONE;
|
|
mQst_ClearDelivery(&grab->delivery, 1);
|
|
}
|
|
|
|
extern void mQst_ClearGrabItemInfo() {
|
|
mQst_ClearGrabItemInfo_common(&l_mqst_grab);
|
|
}
|
|
|
|
extern void mQst_CheckGrabItem(mActor_name_t item, int pocket_idx) {
|
|
Private_c* priv = Common_Get(now_private);
|
|
mQst_grab_c* grab = &l_mqst_grab;
|
|
mQst_delivery_c* delivery = priv->deliveries;
|
|
mQst_errand_c* errand = priv->errands;
|
|
u32 item_cond = priv->inventory.item_conditions;
|
|
int i;
|
|
|
|
if (pocket_idx >= 0 && pocket_idx < mPr_POCKETS_SLOT_COUNT) {
|
|
mQst_ClearGrabItemInfo_common(grab);
|
|
delivery += pocket_idx;
|
|
|
|
if (mQst_CheckFreeQuest(&delivery->base) == FALSE) {
|
|
grab->item = item;
|
|
grab->pocket_idx = pocket_idx;
|
|
grab->type = mQst_QUEST_TYPE_DELIVERY;
|
|
mQst_CopyDelivery(&grab->delivery, delivery);
|
|
mQst_ClearDelivery(delivery, 1);
|
|
}
|
|
|
|
if ((u32)grab->type == mQst_QUEST_TYPE_NONE && mPr_GET_ITEM_COND(item_cond, pocket_idx) == mPr_ITEM_COND_QUEST) {
|
|
|
|
for (i = 0; i < mPr_ERRAND_QUEST_NUM; i++) {
|
|
if (mQst_CheckFreeQuest(&errand->base) == FALSE && errand->pockets_idx == pocket_idx && errand->item == item) {
|
|
grab->item = item;
|
|
grab->pocket_idx = i;
|
|
grab->type = mQst_QUEST_TYPE_ERRAND;
|
|
|
|
break;
|
|
}
|
|
|
|
errand++;
|
|
}
|
|
}
|
|
|
|
if ((u32)grab->type == mQst_QUEST_TYPE_NONE && item != EMPTY_NO) {
|
|
grab->item = item;
|
|
}
|
|
}
|
|
}
|
|
|
|
extern void mQst_CheckPutItem(mActor_name_t item, int pocket_idx) {
|
|
Private_c* priv = Common_Get(now_private);
|
|
mQst_delivery_c t_delivery;
|
|
mQst_delivery_c* deliveries = priv->deliveries;
|
|
mQst_errand_c* errands = priv->errands;
|
|
mQst_grab_c* grab = &l_mqst_grab;
|
|
mActor_name_t slot_item;
|
|
int grab_idx = grab->pocket_idx;
|
|
|
|
if (pocket_idx >= 0 && pocket_idx < mPr_POCKETS_SLOT_COUNT) {
|
|
slot_item = priv->inventory.pockets[pocket_idx];
|
|
|
|
if (grab->item != RSV_NO && item == grab->item) {
|
|
switch (grab->type) {
|
|
case mQst_QUEST_TYPE_DELIVERY:
|
|
{
|
|
|
|
mQst_CopyDelivery(&t_delivery, &grab->delivery);
|
|
mQst_CheckGrabItem(slot_item, pocket_idx);
|
|
mQst_CopyDelivery(deliveries + pocket_idx, &t_delivery);
|
|
|
|
break;
|
|
}
|
|
|
|
case mQst_QUEST_TYPE_ERRAND:
|
|
{
|
|
mQst_CheckGrabItem(slot_item, pocket_idx);
|
|
errands[grab_idx].pockets_idx = pocket_idx;
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
mQst_CheckGrabItem(slot_item, pocket_idx);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
mQst_CheckGrabItem(slot_item, pocket_idx);
|
|
}
|
|
}
|
|
}
|
|
|
|
extern int mQst_CheckNpcExistbyItemIdx(int idx, int sender_or_receipient) {
|
|
int res = FALSE;
|
|
|
|
if (idx >= 0 && idx < mPr_POCKETS_SLOT_COUNT) {
|
|
int delivery_idx = mQst_GetDeliveryIdxbyItemIdx(idx);
|
|
if (delivery_idx != -1) {
|
|
mQst_delivery_c* delivery = Common_Get(now_private)->deliveries + delivery_idx;
|
|
if (sender_or_receipient == mQst_CHECK_NPC_RECEIPIENT) {
|
|
if (mNpc_SearchAnimalPersonalID(&delivery->recipient) != -1) {
|
|
res = TRUE;
|
|
}
|
|
}
|
|
else {
|
|
if (mNpc_SearchAnimalPersonalID(&delivery->sender) != -1) {
|
|
res = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
int errand_idx = mQst_GetErrandIdxbyItemIdx(idx);
|
|
|
|
if (errand_idx != -1) {
|
|
mQst_errand_c* errand = Common_Get(now_private)->errands + errand_idx;
|
|
if (sender_or_receipient == mQst_CHECK_NPC_RECEIPIENT) {
|
|
if (mNpc_SearchAnimalPersonalID(&errand->recipient) != -1) {
|
|
res = TRUE;
|
|
}
|
|
}
|
|
else {
|
|
if (mNpc_SearchAnimalPersonalID(&errand->sender) != -1) {
|
|
res = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
extern int mQst_GetToFromName(u8* to_name, u8* from_name, int idx) {
|
|
int res = FALSE;
|
|
|
|
if (idx >= 0 && idx < mPr_POCKETS_SLOT_COUNT) {
|
|
int delivery_idx = mQst_GetDeliveryIdxbyItemIdx(idx);
|
|
|
|
if (delivery_idx != -1) {
|
|
mQst_delivery_c* delivery = Common_Get(now_private)->deliveries + delivery_idx;
|
|
|
|
mNpc_GetNpcWorldNameAnm(to_name, &delivery->recipient);
|
|
mNpc_GetNpcWorldNameAnm(from_name, &delivery->sender);
|
|
|
|
res = TRUE;
|
|
}
|
|
else {
|
|
int errand_idx = mQst_GetErrandIdxbyItemIdx(idx);
|
|
|
|
if (errand_idx != -1) {
|
|
mQst_errand_c* errand = Common_Get(now_private)->errands + errand_idx;
|
|
|
|
mNpc_GetNpcWorldNameAnm(to_name, &errand->recipient);
|
|
|
|
if (mEv_CheckFirstJob() == TRUE && errand->errand_type == mQst_ERRAND_TYPE_FIRST_JOB) {
|
|
mNpc_GetActorWorldName(from_name, SP_NPC_SHOP_MASTER);
|
|
}
|
|
else {
|
|
mNpc_GetNpcWorldNameAnm(from_name, &errand->sender);
|
|
}
|
|
|
|
res = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
extern int mQst_GetOccuredContestIdx(int kind) {
|
|
Animal_c* animal = Save_Get(animals);
|
|
int res = -1;
|
|
int i;
|
|
|
|
for (i = 0; i < ANIMAL_NUM_MAX; i++) {
|
|
if (animal->contest_quest.base.quest_type == mQst_QUEST_TYPE_CONTEST && (u32)animal->contest_quest.base.quest_kind == kind) {
|
|
res = i;
|
|
break;
|
|
}
|
|
|
|
animal++;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
extern int mQst_GetFlowerSeedNum(int block_x, int block_z) {
|
|
return mFI_GetItemNumOnBlockInField(block_x, block_z, FLOWER_LEAVES_PANSIES0, FLOWER_TULIP2);
|
|
}
|
|
|
|
extern int mQst_GetFlowerNum(int block_x, int block_z) {
|
|
return mFI_GetItemNumOnBlockInField(block_x, block_z, FLOWER_PANSIES0, FLOWER_TULIP2);
|
|
}
|
|
|
|
extern int mQst_GetNullNoNum(int block_x, int block_z) {
|
|
return mFI_GetItemNumOnBlockInField(block_x, block_z, EMPTY_NO, EMPTY_NO);
|
|
}
|
|
|
|
extern void mQst_SetItemNameStr(mActor_name_t item, int string_no) {
|
|
u8 name[mIN_ITEM_NAME_LEN];
|
|
|
|
if (item != EMPTY_NO) {
|
|
int article_no;
|
|
|
|
mIN_copy_name_str(name, item);
|
|
article_no = mIN_get_item_article(item);
|
|
mMsg_Set_item_str_art(mMsg_Get_base_window_p(), string_no, name, mIN_ITEM_NAME_LEN, article_no);
|
|
}
|
|
}
|
|
|
|
extern void mQst_SetItemNameFreeStr(mActor_name_t item, int string_no) {
|
|
u8 name[mIN_ITEM_NAME_LEN];
|
|
|
|
if (item != EMPTY_NO) {
|
|
int article_no;
|
|
|
|
mIN_copy_name_str(name, item);
|
|
article_no = mIN_get_item_article(item);
|
|
mMsg_Set_free_str_art(mMsg_Get_base_window_p(), string_no, name, mIN_ITEM_NAME_LEN, article_no);
|
|
}
|
|
}
|
|
|
|
static mActor_name_t mQst_GetPresent(int rank) {
|
|
int category = -1;
|
|
int list = -1;
|
|
mActor_name_t item = 0;
|
|
|
|
switch (rank) {
|
|
case mQst_LETTER_RANK_3:
|
|
case mQst_LETTER_RANK_7:
|
|
category = mSP_KIND_CLOTH;
|
|
list = mSP_LISTTYPE_ABC;
|
|
break;
|
|
|
|
case mQst_LETTER_RANK_4:
|
|
category = mSP_KIND_FURNITURE;
|
|
list = mSP_LISTTYPE_ABC;
|
|
break;
|
|
|
|
case mQst_LETTER_RANK_5:
|
|
{
|
|
list = mSP_LISTTYPE_ABC;
|
|
|
|
if ((mQst_GetRandom(4) & 1) == 0) {
|
|
category = mSP_KIND_CARPET;
|
|
}
|
|
else {
|
|
category = mSP_KIND_WALLPAPER;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case mQst_LETTER_RANK_6:
|
|
item = Save_Get(fruit);
|
|
break;
|
|
|
|
case mQst_LETTER_RANK_8:
|
|
category = mSP_KIND_CLOTH;
|
|
list = mSP_LISTTYPE_RARE;
|
|
break;
|
|
|
|
case mQst_LETTER_RANK_9:
|
|
item = mFI_GetOtherFruit();
|
|
break;
|
|
|
|
case mQst_LETTER_RANK_10:
|
|
category = mSP_KIND_FURNITURE;
|
|
list = mSP_LISTTYPE_RARE;
|
|
break;
|
|
|
|
case mQst_LETTER_RANK_11:
|
|
{
|
|
list = mSP_LISTTYPE_RARE;
|
|
|
|
if ((mQst_GetRandom(4) & 1) == 0) {
|
|
category = mSP_KIND_CARPET;
|
|
}
|
|
else {
|
|
category = mSP_KIND_WALLPAPER;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (category != -1 && list != -1) {
|
|
mSP_SelectRandomItem_New(NULL, &item, 1, NULL, 0, category, list, FALSE);
|
|
}
|
|
|
|
return item;
|
|
}
|
|
|
|
static void mQst_GetRemailData(Mail_c* letter, PersonalID_c* recipient_id, AnmPersonalID_c* sender_id, int rank, mActor_name_t present) {
|
|
int handbill_no;
|
|
int looks = sender_id->looks;
|
|
u8 name_buf[mIN_ITEM_NAME_LEN];
|
|
u8 header[MAIL_HEADER2_LEN];
|
|
u8 footer[MAIL_FOOTER2_LEN];
|
|
int header_back_pos;
|
|
|
|
mMl_clear_mail(letter);
|
|
handbill_no = 0x75 + (rank * mNpc_LOOKS_NUM + looks);
|
|
mNpc_GetNpcWorldNameAnm(name_buf, sender_id);
|
|
mHandbill_Set_free_str(mHandbill_FREE_STR6, name_buf, ANIMAL_NAME_LEN);
|
|
|
|
if (present != EMPTY_NO) {
|
|
mIN_copy_name_str(name_buf, present);
|
|
mHandbill_Set_free_str(mHandbill_FREE_STR0, name_buf, mIN_ITEM_NAME_LEN);
|
|
}
|
|
|
|
mHandbill_Load_HandbillFromRom2(header, MAIL_HEADER2_LEN, &header_back_pos, footer, MAIL_FOOTER2_LEN, letter->content.body, handbill_no);
|
|
mem_copy(letter->content.header, header, MAIL_HEADER_LEN);
|
|
mem_copy(letter->content.footer, footer, MAIL_FOOTER_LEN);
|
|
letter->content.header_back_start = header_back_pos;
|
|
letter->content.font = mMl_FONT_0;
|
|
letter->content.mail_type = 0;
|
|
|
|
mPr_CopyPersonalID(&letter->header.recipient.personalID, recipient_id);
|
|
letter->header.recipient.type = mMl_NAME_TYPE_PLAYER;
|
|
|
|
mMl_set_mail_name_npcinfo(&letter->header.sender, sender_id);
|
|
|
|
letter->content.paper_type = (ITM_PAPER22 - ITM_PAPER_START); // festive paper
|
|
letter->present = present;
|
|
}
|
|
|
|
extern int mQst_SendRemail(mQst_contest_c* contest, AnmPersonalID_c* sender_id) {
|
|
PersonalID_c* recipient_id = &contest->player_id;
|
|
mHm_hs_c* house;
|
|
int res = FALSE;
|
|
|
|
if (mPr_NullCheckPersonalID(recipient_id) == FALSE) {
|
|
int priv_idx = mPr_GetPrivateIdx(recipient_id);
|
|
|
|
if (priv_idx != -1) {
|
|
house = Save_GetPointer(homes[mHS_get_arrange_idx(priv_idx)]);
|
|
|
|
if (mPr_CheckCmpPersonalID(recipient_id, &house->ownerID) == TRUE) {
|
|
int free_mail_idx = mMl_chk_mail_free_space(house->mailbox, HOME_MAILBOX_SIZE);
|
|
|
|
if (free_mail_idx != -1) {
|
|
Mail_c letter;
|
|
|
|
mQst_GetRemailData(&letter, recipient_id, sender_id, contest->info.letter_data.score, contest->info.letter_data.present);
|
|
mMl_copy_mail(&house->mailbox[free_mail_idx], &letter);
|
|
|
|
res = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
static u8 mQst_GetMailRank(u8* body, mActor_name_t present) {
|
|
u8 rank = mQst_LETTER_RANK_MIN;
|
|
int length = 0;
|
|
u8 score_bonus = mNpc_CheckNormalMail_length(&length, body);
|
|
|
|
if (length >= mQst_LETTER_GOOD_LENGTH) {
|
|
rank = mQst_LETTER_RANK_2;
|
|
}
|
|
else if (length >= mQst_LETTER_OKAY_LENGTH) {
|
|
rank = mQst_LETTER_RANK_1;
|
|
}
|
|
|
|
if (score_bonus >= mNpc_LETTER_RANK_OK) {
|
|
rank += mQst_LETTER_SCORE_BONUS;
|
|
}
|
|
|
|
if (present != EMPTY_NO) {
|
|
rank += mQst_LETTER_PRESENT_BONUS;
|
|
}
|
|
|
|
return rank;
|
|
}
|
|
|
|
extern void mQst_SetReceiveLetter(mQst_contest_c* contest, PersonalID_c* sender_id, u8* body, mActor_name_t present) {
|
|
if (
|
|
contest->base.quest_type == mQst_QUEST_TYPE_CONTEST &&
|
|
contest->base.quest_kind == mQst_CONTEST_KIND_LETTER &&
|
|
mPr_NullCheckPersonalID(&contest->player_id) == TRUE &&
|
|
contest->base.progress == 2
|
|
) {
|
|
mPr_CopyPersonalID(&contest->player_id, sender_id);
|
|
contest->base.progress = 1;
|
|
contest->info.letter_data.score = mQst_GetMailRank(body, present);
|
|
contest->info.letter_data.present = mQst_GetPresent(contest->info.letter_data.score);
|
|
}
|
|
}
|
|
|
|
extern mQst_errand_c* mQst_GetFirstJobData() {
|
|
mQst_errand_c* errand = Common_Get(now_private)->errands;
|
|
mQst_errand_c* errand_p = errand;
|
|
int i;
|
|
int j;
|
|
mQst_errand_c* selected_errand = NULL;
|
|
|
|
/* Try to find any current 'first job' errand quest */
|
|
for (i = 0; i < mPr_ERRAND_QUEST_NUM; i++) {
|
|
if (errand_p->base.quest_type == mQst_QUEST_TYPE_ERRAND && errand_p->errand_type == mQst_ERRAND_TYPE_FIRST_JOB) {
|
|
selected_errand = errand_p;
|
|
break;
|
|
}
|
|
|
|
errand_p++;
|
|
}
|
|
|
|
if (selected_errand == NULL) {
|
|
/* Try to find a free quest slot */
|
|
|
|
for (j = 0; j < mPr_ERRAND_QUEST_NUM; j++) {
|
|
if (mQst_CheckFreeQuest(&errand->base) == TRUE) {
|
|
selected_errand = errand;
|
|
break;
|
|
}
|
|
|
|
errand++;
|
|
}
|
|
|
|
}
|
|
|
|
return selected_errand; /* This can be NULL */
|
|
}
|
|
|
|
static int mQst_CheckFirstJobQuest(mQst_errand_c* errand) {
|
|
if (errand != NULL && errand->base.quest_type == mQst_QUEST_TYPE_ERRAND && errand->errand_type == mQst_ERRAND_TYPE_FIRST_JOB) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
extern int mQst_CheckFirstJobQuestbyItemIdx(int idx) {
|
|
int res = FALSE;
|
|
|
|
if (idx >= 0 && idx < mPr_POCKETS_SLOT_COUNT) {
|
|
int errand_idx = mQst_GetErrandIdxbyItemIdx(idx);
|
|
|
|
if (errand_idx != -1) {
|
|
res = mQst_CheckFirstJobQuest(Common_Get(now_private)->errands + errand_idx);
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
extern int mQst_CheckFirstJobFin(mQst_errand_c* errand) {
|
|
int res = FALSE;
|
|
|
|
if (errand->base.progress == 0) {
|
|
res = TRUE;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
extern int mQst_CheckRemoveTarget(mQst_errand_c* errand) {
|
|
int res = FALSE;
|
|
|
|
if (errand != NULL && mNpc_SearchAnimalinfo(Save_Get(animals), errand->recipient.npc_id, ANIMAL_NUM_MAX) == -1) {
|
|
res = TRUE;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
extern void mQst_SetFirstJobStart(mQst_errand_c* errand) {
|
|
int i;
|
|
|
|
if (errand != NULL) {
|
|
mQst_ClearErrand(errand, 1);
|
|
errand->base.quest_type = mQst_QUEST_TYPE_ERRAND;
|
|
errand->base.quest_kind = mQst_ERRAND_FIRSTJOB_START;
|
|
errand->base.progress = 0;
|
|
errand->errand_type = mQst_ERRAND_TYPE_FIRST_JOB;
|
|
|
|
for (i = 0; i < mQst_ERRAND_FIRST_JOB_ANIMAL_NUM; i++) {
|
|
mNpc_ClearAnimalPersonalID(errand->info.first_job.used_ids + i);
|
|
}
|
|
}
|
|
}
|
|
|
|
extern void mQst_SetFirstJobChangeCloth(mQst_errand_c* errand, mActor_name_t item) {
|
|
if (errand == NULL) {
|
|
return;
|
|
}
|
|
|
|
errand->base.quest_type = mQst_QUEST_TYPE_ERRAND;
|
|
errand->base.quest_kind = mQst_ERRAND_FIRSTJOB_CHANGE_CLOTH;
|
|
errand->base.time_limit_enabled = FALSE;
|
|
errand->base.progress = 2;
|
|
errand->base.give_reward = FALSE;
|
|
|
|
errand->errand_type = mQst_ERRAND_TYPE_FIRST_JOB;
|
|
errand->item = item;
|
|
}
|
|
|
|
extern void mQst_SetFirstJobSeed(mQst_errand_c* errand) {
|
|
if (errand == NULL) {
|
|
return;
|
|
}
|
|
|
|
errand->base.quest_type = mQst_QUEST_TYPE_ERRAND;
|
|
errand->base.quest_kind = mQst_ERRAND_FIRSTJOB_PLANT_FLOWER;
|
|
errand->base.time_limit_enabled = FALSE;
|
|
errand->base.progress = 2;
|
|
errand->base.give_reward = FALSE;
|
|
|
|
errand->errand_type = mQst_ERRAND_TYPE_FIRST_JOB;
|
|
}
|
|
|
|
extern void mQst_SetFirstJobHello(mQst_errand_c* errand) {
|
|
if (errand == NULL) {
|
|
return;
|
|
}
|
|
|
|
errand->base.quest_type = mQst_QUEST_TYPE_ERRAND;
|
|
errand->base.quest_kind = mQst_ERRAND_FIRSTJOB_INTRODUCTIONS;
|
|
errand->base.time_limit_enabled = FALSE;
|
|
errand->base.progress = 2;
|
|
errand->base.give_reward = FALSE;
|
|
|
|
errand->errand_type = mQst_ERRAND_TYPE_FIRST_JOB;
|
|
}
|
|
|
|
extern void mQst_SetFirstJobFurniture(mQst_errand_c* errand, AnmPersonalID_c* pid, mActor_name_t item, u8 slot) {
|
|
if (errand != NULL) {
|
|
errand->base.quest_type = mQst_QUEST_TYPE_ERRAND;
|
|
errand->base.quest_kind = mQst_ERRAND_FIRSTJOB_DELIVER_FTR;
|
|
errand->base.time_limit_enabled = FALSE;
|
|
errand->base.progress = 2;
|
|
errand->base.give_reward = FALSE;
|
|
|
|
mNpc_CopyAnimalPersonalID(&errand->recipient, pid);
|
|
mNpc_CopyAnimalPersonalID(&errand->info.first_job.used_ids[0], pid);
|
|
errand->info.first_job.used_num = 1;
|
|
errand->pockets_idx = slot;
|
|
errand->errand_type = mQst_ERRAND_TYPE_FIRST_JOB;
|
|
errand->item = item;
|
|
}
|
|
}
|
|
|
|
static void mQst_SetFirstJobLetter_common(mQst_errand_c* errand, AnmPersonalID_c* pid, u8 kind) {
|
|
if (errand != NULL) {
|
|
errand->base.quest_type = mQst_QUEST_TYPE_ERRAND;
|
|
errand->base.quest_kind = (u32)kind;
|
|
errand->base.time_limit_enabled = FALSE;
|
|
errand->base.progress = 2;
|
|
errand->base.give_reward = FALSE;
|
|
|
|
mNpc_CopyAnimalPersonalID(&errand->recipient, pid);
|
|
errand->errand_type = mQst_ERRAND_TYPE_FIRST_JOB;
|
|
mNpc_CopyAnimalPersonalID(&errand->info.first_job.used_ids[1], pid);
|
|
errand->info.first_job.used_num = 2;
|
|
}
|
|
}
|
|
|
|
extern void mQst_SetFirstJobLetter(mQst_errand_c* errand, AnmPersonalID_c* pid) {
|
|
mQst_SetFirstJobLetter_common(errand, pid, mQst_ERRAND_FIRSTJOB_SEND_LETTER);
|
|
}
|
|
|
|
extern void mQst_SetFirstJobLetter2(mQst_errand_c* errand, AnmPersonalID_c* pid) {
|
|
mQst_SetFirstJobLetter_common(errand, pid, mQst_ERRAND_FIRSTJOB_SEND_LETTER2);
|
|
}
|
|
|
|
extern void mQst_SetFirstJobOpenQuest(mQst_errand_c* errand) {
|
|
if (errand != NULL) {
|
|
errand->base.quest_type = mQst_QUEST_TYPE_ERRAND;
|
|
errand->base.quest_kind = mQst_ERRAND_FIRSTJOB_OPEN;
|
|
errand->base.time_limit_enabled = FALSE;
|
|
errand->base.progress = 2;
|
|
errand->base.give_reward = FALSE;
|
|
|
|
mNpc_ClearAnimalPersonalID(&errand->recipient);
|
|
errand->errand_type = mQst_ERRAND_TYPE_FIRST_JOB;
|
|
mEv_EventON(mEv_SAVED_FJOPENQUEST_PLR0 + Common_Get(player_no));
|
|
}
|
|
}
|
|
|
|
extern void mQst_SetFirstJobCarpet(mQst_errand_c* errand, AnmPersonalID_c* pid, mActor_name_t item, u8 slot) {
|
|
if (errand != NULL) {
|
|
errand->base.quest_type = mQst_QUEST_TYPE_ERRAND;
|
|
errand->base.quest_kind = mQst_ERRAND_FIRSTJOB_DELIVER_CARPET;
|
|
errand->base.time_limit_enabled = FALSE;
|
|
errand->base.progress = 2;
|
|
errand->base.give_reward = FALSE;
|
|
|
|
mNpc_CopyAnimalPersonalID(&errand->recipient, pid);
|
|
errand->pockets_idx = slot;
|
|
errand->errand_type = mQst_ERRAND_TYPE_FIRST_JOB;
|
|
errand->item = item;
|
|
}
|
|
}
|
|
|
|
static void mQst_SetFirstJobAxe_common(mQst_errand_c* errand, AnmPersonalID_c* pid, mActor_name_t item, u8 slot, u8 kind) {
|
|
if (errand != NULL) {
|
|
errand->base.quest_type = mQst_QUEST_TYPE_ERRAND;
|
|
errand->base.quest_kind = kind;
|
|
errand->base.time_limit_enabled = FALSE;
|
|
errand->base.progress = 2;
|
|
errand->base.give_reward = FALSE;
|
|
|
|
mNpc_CopyAnimalPersonalID(&errand->recipient, pid);
|
|
errand->pockets_idx = slot;
|
|
errand->errand_type = mQst_ERRAND_TYPE_FIRST_JOB;
|
|
errand->item = item;
|
|
}
|
|
}
|
|
|
|
extern void mQst_SetFirstJobAxe(mQst_errand_c* errand, AnmPersonalID_c* pid, mActor_name_t item, u8 slot) {
|
|
mQst_SetFirstJobAxe_common(errand, pid, item, slot, mQst_ERRAND_FIRSTJOB_DELIVER_AXE);
|
|
}
|
|
|
|
extern void mQst_SetFirstJobAxe2(mQst_errand_c* errand, AnmPersonalID_c* pid, mActor_name_t item, u8 slot) {
|
|
mQst_SetFirstJobAxe_common(errand, pid, item, slot, mQst_ERRAND_FIRSTJOB_DELIVER_AXE2);
|
|
}
|
|
|
|
extern void mQst_SetFirstJobNotice(mQst_errand_c* errand) {
|
|
if (errand != NULL) {
|
|
errand->base.quest_type = mQst_QUEST_TYPE_ERRAND;
|
|
errand->base.quest_kind = mQst_ERRAND_FIRSTJOB_POST_NOTICE;
|
|
errand->base.time_limit_enabled = FALSE;
|
|
errand->base.progress = 2;
|
|
errand->base.give_reward = FALSE;
|
|
|
|
mNpc_ClearAnimalPersonalID(&errand->recipient);
|
|
errand->errand_type = mQst_ERRAND_TYPE_FIRST_JOB;
|
|
}
|
|
}
|
|
|
|
extern int mQst_GetRandom(int max) {
|
|
return RANDOM(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) {
|
|
int generate_random_item = 1;
|
|
|
|
if (category == mSP_KIND_FURNITURE) {
|
|
generate_random_item = RANDOM(10);
|
|
}
|
|
|
|
/* 1/10 chance to roll an item from the villager's house if the "goods" kind is furniture */
|
|
if (generate_random_item != 0) {
|
|
mSP_SelectRandomItem_New(NULL, item, 1, exist_table, exist_num, category, list, FALSE);
|
|
}
|
|
else {
|
|
*item = mNpc_GetNpcFurniture(pid);
|
|
|
|
if (*item == EMPTY_NO) {
|
|
mSP_SelectRandomItem_New(NULL, item, 1, exist_table, exist_num, category, list, FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
extern int mQst_CheckSoccerTarget(ACTOR* actor) {
|
|
int res = FALSE;
|
|
|
|
if (actor != NULL && actor->part == ACTOR_PART_NPC) {
|
|
int npc_idx = mQst_GetOccuredContestIdx(mQst_CONTEST_KIND_SOCCER);
|
|
|
|
if (npc_idx != -1) {
|
|
Animal_c* animal = Save_GetPointer(animals[npc_idx]);
|
|
|
|
if (animal->contest_quest.base.progress == 2) {
|
|
res = mNpc_CheckCmpAnimalPersonalID(&animal->id, &((NPC_ACTOR*)actor)->npc_info.animal->id);
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
extern void mQst_NextSoccer(ACTOR* actor) {
|
|
mQst_contest_c* contest;
|
|
int looks = mNpc_LOOKS_GIRL;
|
|
NPC_ACTOR* npc_actor = (NPC_ACTOR*)actor;
|
|
int npc_idx = mQst_GetOccuredContestIdx(mQst_CONTEST_KIND_SOCCER);
|
|
|
|
|
|
if (npc_idx != -1 && npc_actor != NULL) {
|
|
contest = &Save_Get(animals[npc_idx]).contest_quest;
|
|
|
|
if (contest->base.progress == 2 && Common_Get(clip).npc_clip != NULL) {
|
|
Animal_c* animal = npc_actor->npc_info.animal;
|
|
|
|
if (animal != NULL) {
|
|
looks = animal->id.looks;
|
|
}
|
|
|
|
if ((*Common_Get(clip).npc_clip->force_call_req_proc)(npc_actor, 0x0D8B + looks) == TRUE) {
|
|
contest->base.progress = 1;
|
|
mPr_CopyPersonalID(&contest->player_id, &Common_Get(now_private)->player_ID);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* @unused int? mQst_CheckBallKeep(...?) */
|
|
|
|
extern void mQst_NextSnowman(xyz_t snowman_pos) {
|
|
int npc_idx = mQst_GetOccuredContestIdx(mQst_CONTEST_KIND_SNOWMAN);
|
|
int block_x;
|
|
int block_z;
|
|
|
|
if (npc_idx != -1) {
|
|
mQst_contest_c* contest;
|
|
Animal_c* animal = Save_GetPointer(animals[npc_idx]);
|
|
|
|
contest = &animal->contest_quest;
|
|
|
|
if (contest->base.progress == 1) {
|
|
if (mFI_Wpos2BlockNum(&block_x, &block_z, snowman_pos) == TRUE && animal->home_info.block_x == block_x && animal->home_info.block_z == block_z) {
|
|
mPr_CopyPersonalID(&contest->player_id, &Common_Get(now_private)->player_ID);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
extern void mQst_BackSnowman(xyz_t snowman_pos) {
|
|
int npc_idx = mQst_GetOccuredContestIdx(mQst_CONTEST_KIND_SNOWMAN);
|
|
int block_x;
|
|
int block_z;
|
|
|
|
if (npc_idx != -1) {
|
|
mQst_contest_c* contest;
|
|
Animal_c* animal = Save_GetPointer(animals[npc_idx]);
|
|
|
|
contest = &animal->contest_quest;
|
|
|
|
if (contest->base.progress == 1) {
|
|
if (mFI_Wpos2BlockNum(&block_x, &block_z, snowman_pos) == TRUE && animal->home_info.block_x == block_x && animal->home_info.block_z == block_z) {
|
|
mPr_ClearPersonalID(&contest->player_id);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
extern void mQst_PrintQuestInfo(gfxprint_t* gfxprint) {
|
|
Private_c* priv = Common_Get(now_private);
|
|
mQst_delivery_c* delivery;
|
|
mQst_errand_c* errand;
|
|
Animal_c* animal = Save_Get(animals);
|
|
int i;
|
|
|
|
if (priv != NULL) {
|
|
delivery = priv->deliveries;
|
|
errand = priv->errands;
|
|
}
|
|
else {
|
|
delivery = Save_Get(private[0]).deliveries;
|
|
errand = Save_Get(private[0]).errands;
|
|
}
|
|
|
|
gfxprint_color(gfxprint, 220, 50, 50, 255);
|
|
gfxprint_locate8x8(gfxprint, 3, 4);
|
|
|
|
for (i = 0; i < mPr_DELIVERY_QUEST_NUM; i++) {
|
|
if (i < 5 || i >= 10) {
|
|
gfxprint_color(gfxprint, 220, 50, 50, 255);
|
|
}
|
|
else {
|
|
gfxprint_color(gfxprint, 50, 50, 220, 255);
|
|
}
|
|
|
|
if (delivery[i].base.quest_type == mQst_QUEST_TYPE_DELIVERY) {
|
|
gfxprint_printf(gfxprint, "%x", delivery[i].base.quest_kind);
|
|
}
|
|
else {
|
|
gfxprint_printf(gfxprint, "*");
|
|
}
|
|
}
|
|
|
|
gfxprint_color(gfxprint, 50, 50, 220, 255);
|
|
|
|
for (i = 0; i < mPr_ERRAND_QUEST_NUM; i++) {
|
|
if (errand[i].base.quest_type == mQst_QUEST_TYPE_ERRAND) {
|
|
gfxprint_printf(gfxprint, "%x", errand[i].base.quest_kind);
|
|
}
|
|
else {
|
|
gfxprint_printf(gfxprint, "*");
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < ANIMAL_NUM_MAX; i++) {
|
|
if (i < 5 || i >= 10) {
|
|
gfxprint_color(gfxprint, 220, 50, 50, 255);
|
|
}
|
|
else {
|
|
gfxprint_color(gfxprint, 50, 50, 220, 255);
|
|
}
|
|
|
|
if (animal[i].contest_quest.base.quest_type == mQst_QUEST_TYPE_CONTEST) {
|
|
gfxprint_printf(gfxprint, "%x", animal[i].contest_quest.base.quest_kind);
|
|
}
|
|
else {
|
|
gfxprint_printf(gfxprint, "*");
|
|
}
|
|
}
|
|
}
|