Files
ac-decomp/rel/m_private.c
T
2023-09-16 10:15:49 -04:00

1502 lines
39 KiB
C

#include "m_private.h"
#include "m_land.h"
#include "m_font.h"
#include "m_lib.h"
#include "libultra/libultra.h"
#include "m_player_lib.h"
#include "m_name_table.h"
#include "libc64/qrand.h"
#include "m_field_info.h"
#include "m_house.h"
#include "m_mail.h"
#include "m_handbill.h"
#include "m_post_office.h"
#include "m_event.h"
#include "m_npc.h"
#include "m_submenu.h"
#include "m_room_type.h"
#include "m_common_data.h"
static Mail_c l_mpr_mail;
Private_c g_foreigner_private;
extern void mPr_ClearPlayerName(u8* buf) {
mem_clear(buf, PLAYER_NAME_LEN, CHAR_SPACE);
}
extern void mPr_CopyPlayerName(u8* dst, u8* src) {
mem_copy(dst, src, PLAYER_NAME_LEN);
}
extern int mPr_NullCheckPlayerName(u8* name_p) {
int res = FALSE;
int i;
for (i = 0; i < PLAYER_NAME_LEN; i++) {
if (name_p[0] != CHAR_SPACE) {
break;
}
name_p++;
}
if (i == PLAYER_NAME_LEN) {
res = TRUE;
}
return res;
}
extern int mPr_CheckCmpPlayerName(u8* name0, u8* name1) {
int res = FALSE;
if (mPr_NullCheckPlayerName(name0) == FALSE && mPr_NullCheckPlayerName(name1) == FALSE) {
res = mem_cmp(name0, name1, PLAYER_NAME_LEN);
}
return res;
}
extern int mPr_GetPlayerName(u8* buf, int player_no) {
PersonalID_c* pid;
int res = FALSE;
if (mLd_PlayerManKindCheckNo(player_no) == FALSE) {
pid = &Save_Get(private[player_no]).player_ID;
if (mPr_NullCheckPersonalID(pid) == FALSE) {
mPr_CopyPlayerName(buf, pid->player_name);
res = TRUE;
}
}
else if (mLd_PlayerManKindCheckNo(Common_Get(player_no)) == TRUE) {
mPr_CopyPlayerName(buf, Common_Get(now_private)->player_ID.player_name);
res = TRUE;
}
return res;
}
extern int mPr_NullCheckPersonalID(PersonalID_c* pid) {
int res = FALSE;
if (pid->land_id == 0xFFFF && mPr_NullCheckPlayerName(pid->player_name) == TRUE) {
res = TRUE;
}
return res;
}
extern void mPr_ClearPersonalID(PersonalID_c* pid) {
mPr_ClearPlayerName(pid->player_name);
mLd_ClearLandName(pid->land_name);
pid->land_id = 0xFFFF;
pid->player_id = 0xFFFF;
}
extern void mPr_ClearAnyPersonalID(PersonalID_c* pid, int count) {
for (count; count != 0; count--) {
mPr_ClearPersonalID(pid);
pid++;
}
}
extern void mPr_CopyPersonalID(PersonalID_c* dst, PersonalID_c* src) {
mem_copy((u8*)dst, (u8*)src, sizeof(PersonalID_c));
}
extern int mPr_CheckCmpPersonalID(PersonalID_c* pid0, PersonalID_c* pid1) {
int res = FALSE;
if (
pid0->land_id == pid1->land_id &&
pid0->player_id == pid1->player_id &&
mLd_CheckCmpLandName(pid0->land_name, pid1->land_name) == TRUE &&
mPr_CheckCmpPlayerName(pid0->player_name, pid1->player_name) == TRUE
) {
res = TRUE;
}
return res;
}
// TODO: this might actually be file-local but I'm not sure, DnM+ inlined it
extern void mPr_ClearPrivateBirthday(mPr_birthday_c* birthday) {
birthday->year = 0xFFFF;
birthday->month = 0xFF;
birthday->day = 0xFF;
}
extern void mPr_ClearAnimalMemory(mPr_animal_memory_c* memory) {
memory->npc_id = 0xFFFF;
mLd_ClearLandName(memory->land_name);
}
extern void mPr_ClearPrivateInfo(Private_c* private_info) {
bzero(private_info, sizeof(Private_c));
mPr_ClearPersonalID(&private_info->player_ID);
private_info->gender = mPr_SEX_MALE;
mQst_ClearDelivery(private_info->deliveries, mPr_DELIVERY_QUEST_NUM);
mQst_ClearErrand(private_info->errands, mPr_ERRAND_QUEST_NUM);
mMl_clear_mail_box(private_info->mail, mPr_INVENTORY_MAIL_COUNT);
mMl_clear_mail_header_common(&private_info->saved_mail_header);
mPlib_change_player_cloth_info_lv2(private_info, ITM_CLOTH001);
mNpc_ClearAnimalPersonalID(&private_info->stored_anm_id);
mPr_ClearPrivateBirthday(&private_info->birthday);
private_info->backgound_texture = ITM_CLOTH226;
mNpc_ClearRemail(&private_info->remail);
mPr_ClearAnimalMemory(&private_info->animal_memory);
mPr_ClearMapInfo(private_info->maps, mPr_FOREIGN_MAP_COUNT);
mMsm_ClearRecord(&private_info->museum_record);
private_info->state_flags = 1;
}
static int mPr_GetRandomFace() {
return (fqrand() * (f32)mPr_FACE_TYPE_NUM);
}
static int mPr_GetRandomOriginalFace() {
Private_c* priv = Save_Get(private);
Private_c* pr2;
//Private_c* pr2;
int j;
int player_exist_num = 0;
int face;
int i;
{
Private_c* pr = priv;
for (i = 0; i < PLAYER_NUM; i++) {
if (pr != NULL && mPr_NullCheckPersonalID(&pr->player_ID) == FALSE) {
player_exist_num++;
}
pr++;
}
}
face = RANDOM(mPr_FACE_TYPE_NUM - player_exist_num);
for (player_exist_num; player_exist_num > 0; player_exist_num--) {
pr2 = priv;
for (j = 0; j < PLAYER_NUM; j++) {
if (pr2 != NULL && mPr_NullCheckPersonalID(&pr2->player_ID) == FALSE && pr2->face == face) {
face++;
if (face >= mPr_FACE_TYPE_NUM) {
face = mPr_FACE_TYPE0;
}
break;
}
pr2++;
}
}
return face;
}
static mActor_name_t mPr_boy_cloth_table[8] = { ITM_CLOTH000, ITM_CLOTH001, ITM_CLOTH002, ITM_CLOTH003, ITM_CLOTH004, ITM_CLOTH005, ITM_CLOTH006, ITM_CLOTH007 };
static mActor_name_t mPr_girl_cloth_table[8] = { ITM_CLOTH008, ITM_CLOTH009, ITM_CLOTH010, ITM_CLOTH011, ITM_CLOTH012, ITM_CLOTH013, ITM_CLOTH014, ITM_CLOTH015 };
static mActor_name_t mPr_GetRandomCloth(u8 sex) {
static mActor_name_t* cloth_table[mPr_SEX_NUM] = { mPr_boy_cloth_table, mPr_girl_cloth_table };
static int cloth_max[mPr_SEX_NUM] = { 8, 8 };
u8 s = sex;
int sel_cloth;
mActor_name_t* t;
mActor_name_t cloth;
if (s >= mPr_SEX_NUM) {
s = mPr_SEX_MALE;
}
t = cloth_table[s];
sel_cloth = RANDOM(cloth_max[s]);
cloth = t[sel_cloth];
return cloth;
}
extern void mPr_SetNowPrivateCloth() {
Private_c* priv = Common_Get(now_private);
if (priv != NULL) {
mPlib_change_player_cloth_info_lv2(priv, mPr_GetRandomCloth(priv->gender));
}
}
extern void mPr_InitPrivateInfo(Private_c* priv) {
mLd_land_info_c* land_info = Save_GetPointer(land_info);
Private_c* o_priv = Save_Get(private);
int id_existed = FALSE;
int face = mPr_GetRandomOriginalFace();
int pid;
int i;
priv->player_ID.land_id = land_info->id;
mLd_CopyLandName(priv->player_ID.land_name, land_info->name);
pid = fqrand() * 253.0f;
for (i = 0; i < PLAYER_NUM - 1; i++) {
int j;
for (j = 0; j < PLAYER_NUM; j++) {
if ((u16)pid == o_priv[j].player_ID.player_id) {
id_existed = TRUE;
pid++; // move to next PID
break;
}
}
if (id_existed == FALSE) {
break;
}
id_existed = FALSE;
}
priv->player_ID.player_id = 0xF000 | pid;
priv->exists = TRUE;
mPlib_change_player_cloth_info_lv2(priv, mPr_GetRandomCloth(mPr_SEX_MALE));
priv->gender = mPr_SEX_MALE;
priv->inventory.loan = 100;
priv->face = face;
for (i = 0; i < mPr_ORIGINAL_DESIGN_COUNT; i++) {
priv->my_org_no_table[i] = i;
}
}
extern void mPr_CopyPrivateInfo(Private_c* dst, Private_c* src) {
bcopy(src, dst, sizeof(Private_c));
}
extern int mPr_CheckPrivate(Private_c* priv) {
int res = FALSE;
if (mLd_CHECK_LAND_ID(priv->player_ID.land_id)) {
res = TRUE;
}
return res;
}
extern int mPr_CheckCmpPrivate(Private_c* priv0, Private_c* priv1) {
int res = FALSE;
if (mPr_CheckCmpPersonalID(&priv0->player_ID, &priv1->player_ID) == TRUE) {
res = TRUE;
}
return res;
}
extern int mPr_GetPrivateIdx(PersonalID_c* pid) {
Private_c* priv = Save_Get(private);
int res = -1;
if (mPr_NullCheckPersonalID(pid) == FALSE) {
int i;
for (i = 0; i < PLAYER_NUM; i++) {
if (mPr_CheckCmpPersonalID(pid, &priv->player_ID) == TRUE) {
res = i;
break;
}
priv++;
}
}
return res;
}
extern int mPr_GetPossessionItemIdx(Private_c* priv, mActor_name_t item) {
int idx = -1;
if (priv != NULL) {
mActor_name_t* pockets = priv->inventory.pockets;
int i;
for (i = 0; i < mPr_POCKETS_SLOT_COUNT; i++) {
mActor_name_t it = *pockets;
if (it == item) {
idx = i;
break;
}
pockets++;
}
}
return idx;
}
extern int mPr_GetPossessionItemIdxWithCond(Private_c* priv, mActor_name_t item, u32 cond) {
int idx = -1;
if (priv != NULL) {
mActor_name_t* pockets = priv->inventory.pockets;
int i;
for (i = 0; i < mPr_POCKETS_SLOT_COUNT; i++) {
mActor_name_t it = *pockets;
if (it == item && cond == mPr_GET_ITEM_COND(priv->inventory.item_conditions, i)) {
idx = i;
break;
}
pockets++;
}
}
return idx;
}
extern int mPr_GetPossessionItemIdxFGTypeWithCond_cancel(Private_c* priv, mActor_name_t fg_type, u32 cond, mActor_name_t cancel_item) {
int idx = -1;
if (priv != NULL) {
mActor_name_t* pockets = priv->inventory.pockets;
int i;
for (i = 0; i < mPr_POCKETS_SLOT_COUNT; i++) {
if (ITEM_NAME_GET_TYPE(*pockets) == fg_type && cond == mPr_GET_ITEM_COND(priv->inventory.item_conditions, i) && *pockets != cancel_item) {
idx = i;
break;
}
pockets++;
}
}
return idx;
}
extern int mPr_GetPossessionItemIdxItem1Category(Private_c* priv, u8 item1_type) {
int idx = -1;
if (priv != NULL) {
mActor_name_t* pockets = priv->inventory.pockets;
int i;
for (i = 0; i < mPr_POCKETS_SLOT_COUNT; i++) {
if (ITEM_NAME_GET_TYPE(*pockets) == NAME_TYPE_ITEM1 && GET_NAME_ITEM1_CATEGORY(*pockets) == item1_type) {
idx = i;
break;
}
pockets++;
}
}
return idx;
}
extern int mPr_GetPossessionItemIdxItem1CategoryWithCond_cancel(Private_c* priv, u8 item1_type, u32 cond, mActor_name_t cancel_item) {
int idx = -1;
if (priv != NULL) {
mActor_name_t* pockets = priv->inventory.pockets;
int i;
for (i = 0; i < mPr_POCKETS_SLOT_COUNT; i++) {
if (ITEM_NAME_GET_TYPE(*pockets) == NAME_TYPE_ITEM1 && GET_NAME_ITEM1_CATEGORY(*pockets) == item1_type && cond == mPr_GET_ITEM_COND(priv->inventory.item_conditions, i) && *pockets != cancel_item) {
idx = i;
break;
}
pockets++;
}
}
return idx;
}
extern int mPr_GetPossessionItemIdxKindWithCond(Private_c* priv, mActor_name_t kind_start, mActor_name_t kind_end, u32 cond) {
int idx = -1;
if (priv != NULL) {
mActor_name_t* pockets = priv->inventory.pockets;
int i;
for (i = 0; i < mPr_POCKETS_SLOT_COUNT; i++) {
if (*pockets >= kind_start && *pockets < kind_end && cond == mPr_GET_ITEM_COND(priv->inventory.item_conditions, i)) {
idx = i;
break;
}
pockets++;
}
}
return idx;
}
extern int mPr_GetPossessionItemSum(Private_c* priv, mActor_name_t item) {
int sum = 0;
if (priv != NULL) {
mActor_name_t* pockets = priv->inventory.pockets;
int i;
for (i = 0; i < mPr_POCKETS_SLOT_COUNT; i++) {
if (*pockets == item) {
sum++;
}
pockets++;
}
}
return sum;
}
extern int mPr_GetPossessionItemSumWithCond(Private_c* priv, mActor_name_t item, u32 cond) {
int sum = 0;
if (priv != NULL) {
mActor_name_t* pockets = priv->inventory.pockets;
int i;
for (i = 0; i < mPr_POCKETS_SLOT_COUNT; i++) {
if (*pockets == item && cond == mPr_GET_ITEM_COND(priv->inventory.item_conditions, i)) {
sum++;
}
pockets++;
}
}
return sum;
}
extern int mPr_GetPossessionItemSumFGTypeWithCond_cancel(Private_c* priv, mActor_name_t fg_type, u32 cond, mActor_name_t cancel_item) {
int sum = 0;
if (priv != NULL) {
mActor_name_t* pockets = priv->inventory.pockets;
int i;
for (i = 0; i < mPr_POCKETS_SLOT_COUNT; i++) {
if (ITEM_NAME_GET_TYPE(*pockets) == fg_type && cond == mPr_GET_ITEM_COND(priv->inventory.item_conditions, i) && *pockets != cancel_item) {
sum++;
}
pockets++;
}
}
return sum;
}
extern int mPr_GetPossessionItemSumItemCategoryWithCond_cancel(Private_c* priv, u8 item1_type, u32 cond, mActor_name_t cancel_item) {
int sum = 0;
if (priv != NULL) {
mActor_name_t* pockets = priv->inventory.pockets;
int i;
for (i = 0; i < mPr_POCKETS_SLOT_COUNT; i++) {
if (ITEM_NAME_GET_TYPE(*pockets) == NAME_TYPE_ITEM1 && GET_NAME_ITEM1_CATEGORY(*pockets) == item1_type && cond == mPr_GET_ITEM_COND(priv->inventory.item_conditions, i) && *pockets != cancel_item) {
sum++;
}
pockets++;
}
}
return sum;
}
extern int mPr_GetPossessionItemSumItemCategoryWithCond(Private_c* priv, u8 item1_type, u32 cond) {
int sum = 0;
if (priv != NULL) {
mActor_name_t* pockets = priv->inventory.pockets;
int i;
for (i = 0; i < mPr_POCKETS_SLOT_COUNT; i++) {
if (ITEM_NAME_GET_TYPE(*pockets) == NAME_TYPE_ITEM1 && GET_NAME_ITEM1_CATEGORY(*pockets) == item1_type && cond == mPr_GET_ITEM_COND(priv->inventory.item_conditions, i)) {
sum++;
}
pockets++;
}
}
return sum;
}
extern int mPr_GetPossessionItemSumKindWithCond(Private_c* priv, mActor_name_t kind_start, mActor_name_t kind_end, u32 cond) {
int sum = 0;
if (priv != NULL) {
mActor_name_t* pockets = priv->inventory.pockets;
int i;
for (i = 0; i < mPr_POCKETS_SLOT_COUNT; i++) {
if (*pockets >= kind_start && *pockets < kind_end && cond == mPr_GET_ITEM_COND(priv->inventory.item_conditions, i)) {
sum++;
}
pockets++;
}
}
return sum;
}
extern void mPr_SetItemCollectBit(mActor_name_t item) {
mActor_name_t ftr_item_no = mRmTp_Item1ItemNo2FtrItemNo_AtPlayerRoom(item, 0);
int item_type;
if ((ftr_item_no >= FTR_FISH00 && ftr_item_no <= FTR_FISH39_WEST) || (ftr_item_no >= FTR_INSECT00 && ftr_item_no <= FTR_INSECT39_WEST)) {
return;
}
item_type = ITEM_NAME_GET_TYPE(ftr_item_no);
if (item_type == NAME_TYPE_FTR0 || item_type == NAME_TYPE_FTR1) {
int ftr_idx = mRmTp_FtrItemNo2FtrIdx(ftr_item_no);
if (ftr_idx >= 0 && ftr_idx < FTR_NUM) {
Common_Get(now_private)->furniture_collected_bitfield[ftr_idx >> 5] |= (1 << (ftr_idx & 31));
}
}
else if (item_type == NAME_TYPE_ITEM1) {
int category = ITEM_NAME_GET_CAT(ftr_item_no);
if (category == ITEM1_CAT_PAPER) {
int idx = (ftr_item_no - ITM_PAPER_START) % 64; // 64 unique stationery
Common_Get(now_private)->paper_collected_bitfield[idx >> 5] |= (1 << (idx & 31));
}
else if (category == ITEM1_CAT_CARPET) {
int idx = ftr_item_no - ITM_CARPET_START;
Common_Get(now_private)->carpet_collected_bitfield[idx >> 5] |= (1 << (idx & 31));
}
else if (category == ITEM1_CAT_WALL) {
int idx = ftr_item_no - ITM_WALL_START;
Common_Get(now_private)->wall_collected_bitfield[idx >> 5] |= (1 << (idx & 31));
}
else if (category == ITEM1_CAT_MINIDISK) {
mActor_name_t idx = ftr_item_no - ITM_MINIDISK_START; // why is this one u16, probably mActor_name_t type or something?
Common_Get(now_private)->music_collected_bitfield[idx >> 5] |= (1 << (idx & 31));
}
}
}
extern mActor_name_t mPr_DummyPresentToTruePresent() {
mActor_name_t true_present = EMPTY_NO;
/* 80% chance of rolling furniture from town's rare list */
if (RANDOM(5) != 0) {
mSP_SelectRandomItem_New(NULL, &true_present, 1, NULL, 0, mSP_KIND_FURNITURE, mSP_LISTTYPE_RARE, FALSE);
}
/* 20% (and default case) to get random non-native fruit */
if (true_present == EMPTY_NO) {
true_present = mFI_GetOtherFruit();
}
return true_present;
}
extern void mPr_SetPossessionItem(Private_c* priv, int idx, mActor_name_t item, u32 cond) {
switch (item) {
case ITM_PRESENT:
{
item = mPr_DummyPresentToTruePresent();
cond = mPr_ITEM_COND_PRESENT;
break;
}
case ITM_GOLDEN_NET_PRESENT:
{
item = ITM_GOLDEN_NET;
cond = mPr_ITEM_COND_PRESENT;
break;
}
case ITM_GOLDEN_AXE_PRESENT:
{
item = ITM_GOLDEN_AXE;
cond = mPr_ITEM_COND_PRESENT;
break;
}
case ITM_GOLDEN_SHOVEL_PRESENT:
{
item = ITM_GOLDEN_SHOVEL;
cond = mPr_ITEM_COND_PRESENT;
break;
}
case ITM_GOLDEN_ROD_PRESENT:
{
item = ITM_GOLDEN_ROD;
cond = mPr_ITEM_COND_PRESENT;
break;
}
}
priv->inventory.pockets[idx] = item;
priv->inventory.item_conditions = ((priv->inventory.item_conditions & (~(u32)(mPr_ITEM_COND_NUM << (idx * 2)))) | (cond << (idx * 2)));
if (cond == mPr_ITEM_COND_NORMAL) {
mPr_SetItemCollectBit(item);
}
}
extern int mPr_SetFreePossessionItem(Private_c* priv, mActor_name_t item, u32 cond) {
int idx = mPr_GetPossessionItemIdx(priv, EMPTY_NO);
int res;
if (idx == -1) {
res = FALSE;
}
else {
mPr_SetPossessionItem(priv, idx, item, cond);
res = TRUE;
}
return res;
}
extern void mPr_AddFirstJobHint(Private_c* priv) {
int hints = priv->hint_count + 1;
if ((hints & 0x7F) >= 10) {
hints = 0x80; // signal all hints have been given
}
priv->hint_count = hints;
}
extern int mPr_GetFirstJobHintTime(Private_c* priv) {
return priv->hint_count & 0x7F;
}
extern int mPr_CheckFirstJobHint(Private_c* priv) {
return (priv->hint_count & 0x80) >> 7;
}
extern s16 mPr_GetMoneyPower() {
s16 money_power = Common_Get(money_power);
Private_c* priv = Common_Get(now_private);
if (priv != NULL) {
switch (priv->destiny.type) {
case mPr_DESTINY_MONEY_LUCK:
{
money_power += 100;
break;
}
case mPr_DESTINY_BAD_LUCK:
{
money_power -= 50;
break;
}
}
}
if (money_power < mPr_MONEY_POWER_MIN) {
money_power = mPr_MONEY_POWER_MIN;
}
return money_power;
}
extern s16 mPr_GetGoodsPower() {
s16 goods_power = Common_Get(goods_power);
Private_c* priv = Common_Get(now_private);
if (priv != NULL) {
switch (priv->destiny.type) {
case mPr_DESTINY_GOODS_LUCK:
{
goods_power += 30;
break;
}
case mPr_DESTINY_BAD_LUCK:
{
goods_power -= 30;
break;
}
}
}
if (goods_power > mPr_GOODS_POWER_MAX) {
return mPr_GOODS_POWER_MAX;
}
if (goods_power < mPr_GOODS_POWER_MIN) {
goods_power = mPr_GOODS_POWER_MIN;
}
return goods_power;
}
extern int mPr_CheckMuseumAddress(Private_c* priv) {
int res = FALSE;
if (priv != NULL && priv->museum_record.contacted) {
res = TRUE;
}
return res;
}
extern int mPr_CheckMuseumInfoMail(Private_c* priv) {
int res = FALSE;
if (priv != NULL && priv->museum_record.send_info_mail) {
res = TRUE;
}
return res;
}
extern Private_c* mPr_GetForeignerP() {
return &g_foreigner_private;
}
extern int mPr_LoadPak_and_SetPrivateInfo2(Private_c* unused_private, u8 player_no) {
Private_c* priv;
int res = FALSE;
if (player_no < mPr_FOREIGNER) {
u32 loan;
mHm_hs_c* house;
Private_c* priv = Save_Get(private + player_no);
if (mPr_CheckCmpPrivate(priv, &g_foreigner_private) == TRUE) {
house = Save_GetPointer(homes[mHS_get_arrange_idx(player_no)]);
loan = priv->inventory.loan;
mPr_CopyPrivateInfo(priv, &g_foreigner_private);
if (mHm_CheckKeepHouseSize(player_no) == FALSE || house->size_info.next_size == mHm_HOMESIZE_STATUE) {
priv->inventory.loan = loan;
}
res = TRUE;
Common_Set(now_private, priv);
Common_Set(player_no, player_no);
}
}
else {
mHm_hs_c* house;
int exist_player;
u32 loan;
int i;
priv = Save_Get(private);
for (i = 0; i < PLAYER_NUM; i++) {
exist_player = mPr_CheckCmpPrivate(priv, &g_foreigner_private);
if (exist_player == TRUE) {
house = Save_GetPointer(homes[mHS_get_arrange_idx(i)]);
loan = priv->inventory.loan;
g_foreigner_private.museum_record.contacted = priv->museum_record.contacted;
mPr_CopyPrivateInfo(priv, &g_foreigner_private);
if (mHm_CheckKeepHouseSize(i) == FALSE || house->size_info.next_size == mHm_HOMESIZE_STATUE) {
priv->inventory.loan = loan;
}
res = TRUE;
Common_Set(now_private, priv);
Common_Set(player_no, i);
break;
}
priv++;
}
if (exist_player == FALSE) {
res = TRUE;
Common_Set(now_private, &g_foreigner_private);
Common_Set(player_no, mPr_FOREIGNER);
}
}
return res;
}
extern void mPr_ClearMotherMailInfo(mPr_mother_mail_info_c* mother_mail) {
mother_mail->date = mTM_rtcTime_ymd_clear_code;
bzero(&mother_mail->data, sizeof(mPr_mother_mail_data_c));
}
static int mPr_GetMotherMailPaperType(int month, int day) {
static u8 paper_table[lbRTC_MONTHS_MAX] = {
13, 49, 32, 12, 62, 14, 19, 11, 59, 46, 47, 17
};
Private_c* priv = Common_Get(now_private);
int paper;
/* TODO: should paper be enums? */
if (priv->birthday.month == month && priv->birthday.day == day) {
paper = 1;
}
else if (month == lbRTC_JANUARY && day == 1) {
paper = 63;
}
else if (month == lbRTC_AUGUST && day == 8) {
paper = 48;
}
else if (month == lbRTC_DECEMBER && day == 24) {
paper = 23;
}
else {
int idx = month - 1;
paper = paper_table[idx];
}
return paper - 1;
}
static void mPr_GetMotherMail(Mail_c* mail, PersonalID_c* pid, mActor_name_t present, int stationery, int mail_no) {
int header_back_pos;
mMl_clear_mail(mail);
mHandbill_Load_HandbillFromRom(mail->content.header, &header_back_pos, mail->content.footer, mail->content.body, mail_no);
mail->content.header_back_start = header_back_pos;
mail->content.font = 0; // TODO: enum
mail->content.mail_type = 4; // TODO: enum, this is "from mom"
mMl_set_to_plname(mail, pid);
mail->present = present;
mail->content.paper_type = stationery;
}
static int mPr_SendMotherMailPost(PersonalID_c* pid, int player_no, mActor_name_t present, int stationery, int mail_no) {
Mail_c* mail;
mHm_hs_c* home;
int res = FALSE;
mail = &l_mpr_mail;
home = Save_GetPointer(homes[mHS_get_arrange_idx(player_no)]);
if (mPr_CheckCmpPersonalID(pid, &home->ownerID) == TRUE) {
int mailbox_idx = mMl_chk_mail_free_space(home->mailbox, HOME_MAILBOX_SIZE);
if (mailbox_idx != -1) {
mPr_GetMotherMail(mail, pid, present, stationery, mail_no);
mMl_copy_mail(&home->mailbox[mailbox_idx], mail);
res = TRUE;
}
else if (mPO_get_keep_mail_sum() < mPO_MAIL_STORAGE_SIZE) {
mPr_GetMotherMail(mail, pid, present, stationery, mail_no);
res = mPO_receipt_proc(mail, mPO_SENDTYPE_MAIL);
}
}
return res;
}
static int mPr_SendMotherMailDate(mPr_mother_mail_info_c* mother_mail, lbRTC_time_c* send_time) {
mActor_name_t present = EMPTY_NO;
int mail_no = -1;
int res = FALSE;
if (Common_Get(now_private)->birthday.month == send_time->month && Common_Get(now_private)->birthday.day == send_time->day) {
mail_no = 0x184 + RANDOM(mPr_MOTHER_MAIL_MONTHLY_NUM);
present = FTR_BIRTHDAY_CAKE;
}
else if (send_time->month == send_time->day) {
int letter_num = (send_time->month - 1) * mPr_MOTHER_MAIL_MONTHLY_NUM + RANDOM(mPr_MOTHER_MAIL_MONTHLY_NUM);
mail_no = 0x164 + letter_num;
if (send_time->month == lbRTC_JANUARY) {
present = ITM_MONEY_10000;
}
else if (letter_num == 18) { // TODO: these probably have enums...
present = ITM_FOOD_MUSHROOM;
}
}
else {
if (send_time->month == lbRTC_APRIL && send_time->day == 1) {
mail_no = 0x180; // April Fools
}
else if (mEv_check_status(mEv_EVENT_MOTHERS_DAY, mEv_STATUS_ACTIVE) == TRUE) {
mail_no = 0x17C;
}
else if (mEv_check_status(mEv_EVENT_FATHERS_DAY, mEv_STATUS_ACTIVE) == TRUE) {
mail_no = 0x17E;
}
else if (send_time->month == lbRTC_DECEMBER && send_time->day == 24) {
mail_no = 0x182; // Toy Day (Christmas)
mSP_SelectRandomItem_New(NULL, &present, 1, NULL, 0, mSP_KIND_FURNITURE, mSP_LISTTYPE_ABC, FALSE);
}
if (mail_no != -1) {
/* Randomize between two letter variants */
mail_no += RANDOM(mPr_MOTHER_MAIL_MONTHLY_NUM);
}
}
if (mail_no != -1) {
if (mPr_SendMotherMailPost(&Common_Get(now_private)->player_ID, Common_Get(player_no), present, mPr_GetMotherMailPaperType(send_time->month, send_time->day), mail_no) == TRUE) {
mTM_set_renew_time(&mother_mail->date, send_time);
}
res = TRUE;
}
return res;
}
static int mPr_CheckMotherMailMonthly(mPr_mother_mail_data_c* send_data, int month, int idx) {
if (month == lbRTC_AUGUST) {
return (send_data->august >> (idx)) & 1; // August gets its own byte because it has more than two event letters
}
else {
int shift = (month - 1) * 2;
int slot = shift / 8;
shift -= slot * 8;
idx += shift;
return (send_data->monthly[slot] >> idx) & 1;
}
}
static int mPr_GetMotherMailMonthlyNotSendNum(mPr_mother_mail_data_c* send_data, int month) {
int slot;
int not_send_num = 0;
int i;
if (month == lbRTC_AUGUST) {
for (i = 0; i < 8; i++) {
if (((send_data->august >> i) & 1) == 0) {
not_send_num++;
}
}
}
else {
u8 byte;
int shift = (month - 1) * 2;
slot = shift / 8;
shift -= slot * 8;
byte = send_data->monthly[slot];
for (i = 0; i < 2; i++) {
if (((byte >> shift) & 1) == 0) {
not_send_num++;
shift++;
}
}
}
return not_send_num;
}
static void mPr_SetMotherMailMonthly(mPr_mother_mail_data_c* send_data, int month, int idx) {
if (month == lbRTC_AUGUST) {
send_data->august |= 1 << idx;
}
else {
/* TODO: almost certainly a fake match */
u8* s;
int slot;
int shift;
shift = (month - 1) * 2;
slot = ((month - 1) * 2) / 8;
shift -= slot * 8;
idx += shift;
s = send_data->monthly + slot;
*s |= 1 << idx;
}
}
#pragma pool_data on
static void mPr_GetMotherMailMonthlyData(mPr_mother_mail_data_c* send_data, int* mail_no, mActor_name_t* present, int* event_no, int month, int not_send_num) {
static int mail_start_no_table[mTM_SEASON_NUM] = { 0x18C, 0x192, 0x186, 0x19E };
static mActor_name_t may_2_item_table[1] = { ITM_CLOTH105 }; // fortune shirt
static mActor_name_t december_2_item_table[6] = {
ITM_CLOTH108, // aurora knit
ITM_CLOTH109, // winter sweater
ITM_CLOTH110, // go-go shirt
ITM_CLOTH144, // deer shirt
ITM_CLOTH145, // blue check shirt
ITM_CLOTH156 // fish knit
};
int max;
int mail_start_idx;
int selected_event;
int i;
*present = EMPTY_NO;
mail_start_idx = 3;
if (month <= lbRTC_FEBRUARY) {
mail_start_idx = 3;
}
else if (month <= lbRTC_MAY) {
mail_start_idx = 0;
}
else if (month <= lbRTC_AUGUST) {
mail_start_idx = 1;
}
else if (month <= lbRTC_NOVEMBER) {
mail_start_idx = 2;
}
*mail_no = mail_start_no_table[mail_start_idx];
selected_event = RANDOM(not_send_num);
max = mPr_MOTHER_MAIL_MONTHLY_NUM;
if (month == lbRTC_AUGUST) {
max = 8;
}
for (i = 0; i < max; i++) {
if (mPr_CheckMotherMailMonthly(send_data, month, i) == FALSE) {
if (selected_event <= 0) {
*event_no = i;
break;
}
selected_event--;
}
}
*mail_no += *event_no + (month - 1 - mail_start_idx * 3) * 2;
if (month == lbRTC_MAY && *event_no == 1) {
*present = may_2_item_table[RANDOM(1)];
}
else if (month == lbRTC_DECEMBER) {
if (*event_no == 0) {
*present = ITM_FOOD_APPLE;
}
else {
*present = december_2_item_table[RANDOM(6)];
}
}
else if (month == lbRTC_NOVEMBER) {
*present = ITM_FOOD_MUSHROOM;
}
}
#pragma pool_data reset
static int mPr_GetMotherMailNormalNotSendNum(mPr_mother_mail_data_c* send_data) {
int not_send_num = 0;
int i;
int j;
for (i = 0; i < mPr_MOTHER_MAIL_NORMAL_NUM; i++) {
for (j = 0; j < 8; j++) {
if (((send_data->normal[i] >> j) & 1) == 0) {
not_send_num++;
}
}
}
return not_send_num;
}
static void mPr_SetMotherMailNormal(mPr_mother_mail_data_c* send_data, int idx) {
int slot = idx / 8;
idx -= (idx / 8) * 8;
send_data->normal[slot] |= (1 << idx);
}
static int mPr_CheckMotherMailNormal(mPr_mother_mail_data_c* send_data, int idx) {
int slot = idx / 8;
idx -= (idx / 8) * 8;
return (send_data->normal[slot] >> idx) & 1;
}
// TODO: we need to make an enum for each player mother mail event id
static void mPr_GetMotherMailNormalData(mPr_mother_mail_data_c* send_data, int* mail_no, mActor_name_t* present, int* event_no, int no_send_num) {
int selected_event;
int i;
*event_no = -1;
selected_event = RANDOM(no_send_num);
for (i = 0; i < 56; i++) {
if (mPr_CheckMotherMailNormal(send_data, i) == FALSE) {
if (selected_event <= 0) {
*event_no = i;
break;
}
selected_event--;
}
}
*mail_no = 0x12C + *event_no;
switch (*event_no) {
case 1:
case 16:
mSP_SelectRandomItem_New(NULL, present, 1, NULL, 0, mSP_KIND_CLOTH, mSP_LISTTYPE_ABC, FALSE);
break;
case 3:
case 21:
case 22:
case 47:
*present = mFI_GetOtherFruit();
break;
case 12:
*present = ITM_MONEY_1000;
break;
case 37:
*present = FTR_PAPA_BEAR;
break;
case 38:
*present = FTR_DRACAENA;
break;
case 40:
mSP_RandomUmbSelect(present, 1);
break;
default:
*present = EMPTY_NO;
break;
}
}
static void mPr_SendMotherMailNormal(mPr_mother_mail_info_c* mother_mail, lbRTC_time_c* send_time) {
int mail_no = -1;
int monthly_not_send_num = 0;
int event_no;
mActor_name_t present = EMPTY_NO;
if (RANDOM(100) < 20) {
int not_send_num = mPr_GetMotherMailNormalNotSendNum(&mother_mail->data);
if (not_send_num == 0) {
bzero(&mother_mail->data, sizeof(mPr_mother_mail_data_c));
monthly_not_send_num = mPr_GetMotherMailMonthlyNotSendNum(&mother_mail->data, send_time->month);
}
if (monthly_not_send_num > 0) {
mPr_GetMotherMailMonthlyData(&mother_mail->data, &mail_no, &present, &event_no, send_time->month, monthly_not_send_num);
if (mPr_SendMotherMailPost(&Common_Get(now_private)->player_ID, Common_Get(player_no), present, mPr_GetMotherMailPaperType(send_time->month, send_time->day), mail_no) == TRUE) {
mPr_SetMotherMailMonthly(&mother_mail->data, send_time->month, event_no);
}
}
else {
mPr_GetMotherMailNormalData(&mother_mail->data, &mail_no, &present, &event_no, not_send_num);
if (mPr_SendMotherMailPost(&Common_Get(now_private)->player_ID, Common_Get(player_no), present, mPr_GetMotherMailPaperType(send_time->month, send_time->day), mail_no) == TRUE) {
mPr_SetMotherMailNormal(&mother_mail->data, event_no);
}
}
}
mTM_set_renew_time(&mother_mail->date, send_time);
}
static void mPr_SendMotherMail(mPr_mother_mail_info_c* mother_mail, lbRTC_time_c* send_time) {
if (mPr_SendMotherMailDate(mother_mail, send_time) == FALSE) {
mPr_SendMotherMailNormal(mother_mail, send_time);
}
}
extern void mPr_SendMailFromMother() {
Private_c* priv = Common_Get(now_private);
u8 player_no = Common_Get(player_no);
lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time);
if (mLd_PlayerManKindCheckNo(player_no) == FALSE && priv != NULL && mPr_NullCheckPersonalID(&priv->player_ID) == FALSE) {
mPr_mother_mail_info_c* mother_mail = Save_GetPointer(mother_mail[player_no]);
lbRTC_ymd_c* mail_date = &mother_mail->date;
if (mail_date->year != mTM_rtcTime_ymd_clear_code.year && mail_date->month != mTM_rtcTime_ymd_clear_code.month && mail_date->day != mTM_rtcTime_ymd_clear_code.day) {
if (mail_date->year != rtc_time->year || mail_date->month != rtc_time->month || mail_date->day != rtc_time->day) {
mPr_SendMotherMail(mother_mail, rtc_time);
}
}
else {
mTM_set_renew_time(mail_date, rtc_time);
}
}
}
static void mPr_GetForeingerAnimalMail(Mail_c* mail, Private_c* priv, mPr_animal_memory_c* anm_mem) {
AnmPersonalID_c anm_pid;
int mail_no;
u8 npc_name[ANIMAL_NAME_LEN];
u8 header[40];
u8 footer[48];
int ofs;
int looks;
int header_back_start;
looks = mNpc_GetLooks(anm_mem->npc_id);
ofs = RANDOM(3);
mail_no = 0xFC;
mail_no += ofs + (u8)looks * 3;
mHandbill_Set_free_str(0, priv->player_ID.player_name, PLAYER_NAME_LEN); // player's name
mNpc_LoadNpcNameString(npc_name, anm_mem->npc_id);
mHandbill_Set_free_str(1, npc_name, ANIMAL_NAME_LEN); // animal's name
mHandbill_Set_free_str(2, anm_mem->land_name, LAND_NAME_SIZE); // animal's current town name
mHandbill_Set_free_str(3, priv->player_ID.land_name, LAND_NAME_SIZE); // player's town name
mHandbill_Load_HandbillFromRom2(header, 40, &header_back_start, footer, 48, mail->content.body, mail_no);
mem_copy(mail->content.header, header, mHandbill_HEADER_LEN);
mem_copy(mail->content.footer, footer, mHandbill_FOOTER_LEN);
mail->content.header_back_start = header_back_start;
mail->content.font = 0;
mail->content.mail_type = 0;
mail->present = EMPTY_NO;
mail->content.paper_type = mNpc_GetPaperType();
anm_pid.npc_id = anm_mem->npc_id;
anm_pid.land_id = mLd_BITMASK;
mLd_CopyLandName(anm_pid.land_name, anm_mem->land_name);
anm_pid.name_id = anm_mem->npc_id;
anm_pid.looks = looks;
mMl_set_mail_name_npcinfo(&mail->header.sender, &anm_pid);
mPr_CopyPersonalID(&mail->header.recipient.personalID, &priv->player_ID);
mail->header.recipient.type = mMl_NAME_TYPE_PLAYER;
}
extern void mPr_SendForeingerAnimalMail(Private_c* priv) {
Mail_c* mail = &l_mpr_mail;
mPr_animal_memory_c* anm_mem = &priv->animal_memory;
if (mLd_PlayerManKindCheck() == FALSE) {
if (anm_mem->npc_id != RSV_NO && ITEM_NAME_GET_TYPE(anm_mem->npc_id) == NAME_TYPE_NPC && mPO_get_keep_mail_sum() < mPO_MAIL_STORAGE_SIZE) {
mMl_clear_mail(mail);
mPr_GetForeingerAnimalMail(mail, priv, anm_mem);
mPO_receipt_proc(mail, mPO_SENDTYPE_MAIL);
mPr_ClearAnimalMemory(anm_mem);
}
}
}
extern void mPr_StartSetCompleteTalkInfo() {
if (mSM_CHECK_ALL_FISH_GET()) {
Common_Get(now_private)->complete_fish_insect_flags |= (1 << 0);
}
if (mSM_CHECK_ALL_INSECT_GET()) {
Common_Get(now_private)->complete_fish_insect_flags |= (1 << 2);
}
}
static void mPr_SetCompleteTalk(u8* comp_insect_fish_flags, int type) {
*comp_insect_fish_flags |= (1 << (type * 2) + 1);
}
static int mPr_GetCompleteTalk(u8 comp_insect_fish_flags, int type) {
return (comp_insect_fish_flags >> ((type * 2) + 1)) & 1;
}
extern void mPr_SetFishCompleteTalk() {
mPr_SetCompleteTalk(&Common_Get(now_private)->complete_fish_insect_flags, 0);
}
extern int mPr_CheckFishCompleteTalk(u8 player_no) {
int res = FALSE;
if (player_no < mPr_FOREIGNER && mPr_GetCompleteTalk(Save_Get(private[player_no]).complete_fish_insect_flags, 0) == TRUE) {
res = TRUE;
}
return res;
}
extern void mPr_SetInsectCompleteTalk() {
mPr_SetCompleteTalk(&Common_Get(now_private)->complete_fish_insect_flags, 1);
}
extern int mPr_CheckInsectCompleteTalk(u8 player_no) {
int res = FALSE;
if (player_no < mPr_FOREIGNER && mPr_GetCompleteTalk(Save_Get(private[player_no]).complete_fish_insect_flags, 1) == TRUE) {
res = TRUE;
}
return res;
}
static int mPr_GetTalkPermission(u8 comp_insect_fish_flags, int type) {
int base = type * 2;
int talk = base + 1;
int res = FALSE;
if (((comp_insect_fish_flags >> base) & 1) == 0 || ((comp_insect_fish_flags >> talk) & 1) == 0) {
res = TRUE;
}
return res;
}
extern int mPr_GetFishCompTalkPermission() {
int res = FALSE;
if (mSM_CHECK_ALL_FISH_GET()) {
res = mPr_GetTalkPermission(Common_Get(now_private)->complete_fish_insect_flags, 0);
}
return res;
}
extern int mPr_GetInsectCompTalkPermission() {
int res = FALSE;
if (mSM_CHECK_ALL_INSECT_GET()) {
res = mPr_GetTalkPermission(Common_Get(now_private)->complete_fish_insect_flags, 1);
}
return res;
}
extern void mPr_ClearMapInfo(mPr_map_info_c* map_info, int max) {
for (max; max != 0; max--) {
mLd_ClearLandName(map_info->land_name);
map_info->land_id = 0;
map_info++;
}
}
static void mPr_CopyMapInfo(mPr_map_info_c* dst, mPr_map_info_c* src) {
mem_copy((u8*)dst, (u8*)src, sizeof(mPr_map_info_c));
}
static void mPr_SetMapThisLand(mPr_map_info_c* map_info) {
if (map_info != NULL) {
mLd_CopyLandName(map_info->land_name, Save_Get(land_info).name);
map_info->land_id = Save_Get(land_info).id;
}
}
static int mPr_GetMapFreeIdx(mPr_map_info_c* map_info, int max) {
int res = -1;
int i;
for (i = 0; i < max; i++) {
if (!mLd_CheckId(map_info->land_id) || mLd_NullCheckLandName(map_info->land_name) == TRUE) {
res = i;
break;
}
map_info++;
}
return res;
}
static int mPr_GetLandMapIdx(mPr_map_info_c* map_info, int max, mLd_land_info_c* land_info) {
int res = -1;
if (map_info != NULL && land_info != NULL) {
int i;
for (i = 0; i < max; i++) {
if (mLd_CheckCmpLand(map_info->land_name, map_info->land_id, land_info->name, land_info->id) == TRUE) {
res = i;
break;
}
map_info++;
}
}
return res;
}
extern int mPr_GetThisLandMapIdx(mPr_map_info_c* map_info, int max) {
return mPr_GetLandMapIdx(map_info, max, Save_GetPointer(land_info));
}
static void mPr_PushMapInfo(mPr_map_info_c* map_info, int max) {
if (map_info != NULL) {
max--;
if (max > 0) {
for (max; max > 0; max--) {
mPr_CopyMapInfo(map_info, map_info + 1);
map_info++;
}
}
mPr_ClearMapInfo(map_info, 1);
}
}
extern void mPr_SetNewMap(mPr_map_info_c* map_info, int max) {
if (map_info != NULL && mPr_GetThisLandMapIdx(map_info, max) == -1) {
int free_idx = mPr_GetMapFreeIdx(map_info, max);
if (free_idx != -1) {
map_info += free_idx;
}
else {
mPr_PushMapInfo(map_info, max);
free_idx = max - 1;
map_info += free_idx;
}
if (map_info != NULL) {
mPr_SetMapThisLand(map_info);
}
}
}
extern void mPr_RenewalMapInfo(mPr_map_info_c* map_info, int max, mLd_land_info_c* land_info) {
mPr_map_info_c map_save;
int map_idx = mPr_GetLandMapIdx(map_info, max, land_info);
if (map_idx != -1) {
mPr_CopyMapInfo(&map_save, map_info + map_idx);
mPr_PushMapInfo(map_info + map_idx, max - map_idx);
map_idx = mPr_GetMapFreeIdx(map_info, max);
if (map_idx != -1) {
mPr_CopyMapInfo(map_info + map_idx, &map_save);
}
}
}
extern void mPr_RandomSetPlayerData_title_demo() {
Private_c* priv = Common_Get(now_private);
int i;
priv->gender = RANDOM(4); // why not RANDOM(2)???
priv->gender &= 1;
mPlib_change_player_cloth_info_lv2(priv, mPr_GetRandomCloth(priv->gender));
priv->face = mPr_GetRandomFace();
for (i = 0; i < mHS_HOUSE_NUM; i++) {
Save_Get(homes[i]).door_original = -1;
}
}
extern void mPr_PrintMapInfo_debug(gfxprint_t* gfxprint) {
Private_c* priv = Common_Get(now_private);
mPr_map_info_c* map_info;
int i;
if (priv != NULL) {
map_info = priv->maps;
gfxprint_color(gfxprint, 30, 100, 100, 255);
gfxprint_locate8x8(gfxprint, 3, 21);
gfxprint_printf(gfxprint, "%04x ", Save_Get(land_info).id);
gfxprint_locate8x8(gfxprint, 3, 22);
gfxprint_color(gfxprint, 30, 200, 70, 255);
for (i = 0; i < mPr_FOREIGN_MAP_COUNT; i++) {
if (i == 4) {
gfxprint_locate8x8(gfxprint, 3, 23);
}
if (mLd_CheckId(map_info->land_id) == TRUE) {
gfxprint_printf(gfxprint, "%04x ", map_info->land_id);
}
else {
gfxprint_printf(gfxprint, "**** ");
}
map_info++;
}
}
}