diff --git a/config/rel_slices.yml b/config/rel_slices.yml index ee4a3a14..f6611521 100644 --- a/config/rel_slices.yml +++ b/config/rel_slices.yml @@ -282,6 +282,11 @@ m_random_field/mRF_GetRandomStepMode.c: m_mail_check_ovl.c: .text: [0x8050F06C, 0x8050F838] .data: [0x8069F320, 0x8069FA40] +m_all_grow_ovl.c: + .text: [0x8050F848, 0x80515340] + .rodata: [0x80649098, 0x80649110] + .data: [0x8069FA68, 0x8069FD08] + .bss: [0x813013E0, 0x81301820] ac_douzou.c: .text: [0x805AD6D8, 0x805AE704] .rodata: [0x8064A7C0, 0x8064A7E8] diff --git a/config/symbols.yml b/config/symbols.yml index 81d13183..89179927 100644 --- a/config/symbols.yml +++ b/config/symbols.yml @@ -21028,6 +21028,7 @@ global: 0x8069FB6C: l_magrw_bee_table 0x8069FB74: l_magrw_ftr_table 0x8069FB7C: l_magrw_smn_table + 0x8069FC6C: check_fg #check_fg$2016 0x8069FD08: Aprilfool_Control_Profile 0x8069FD88: Groundhog_Control_Profile 0x8069FDD0: Mscore_Control_Profile diff --git a/include/m_all_grow_ovl.h b/include/m_all_grow_ovl.h index f898695c..e21f4824 100644 --- a/include/m_all_grow_ovl.h +++ b/include/m_all_grow_ovl.h @@ -4,6 +4,8 @@ #include "types.h" #include "m_time.h" #include "m_field_info.h" +#include "m_field_make.h" +#include "m_private.h" #ifdef __cplusplus extern "C" { @@ -11,9 +13,153 @@ extern "C" { #define mAGrw_FOSSIL_NUM 5 #define mAGrw_HANIWA_NUM 3 +#define mAGrw_FTR_TREE_NUM 2 +#define mAGrw_MAX_PAST_DAYS 5 +#define mAGrw_GRASS_TABLE_NUM 12 +#define mAGrw_MONEY_TREE_NUM 30 +#define mAGrw_MAX_TREES_PER_BLOCK 32 +#define mAGrw_ISL_TREE_MAX_LINE 3 +#define mAGrw_ISL_MAX_TREES_PER_BLOCK 15 +#define mAGrw_DUMP_ITEM_NUM 2 +#define mAGrw_GRASS_PER_DAY 5 + +enum { + mAGrw_GROW_FIRST, + mAGrw_GROW, + mAGrw_GROW_FIRST_FORCE, /* Used when you go back in time */ + + mAGrw_GROW_ISLAND_FIRST, + mAGrw_GROW_ISLAND, + mAGrw_GROW_ISLAND_FIRST_FORCE, /* Used when you go back in time */ + + mAGrw_GROW_NUM +}; + +enum { + mAGrw_TREE000, + mAGrw_TREE001, + mAGrw_TREE002, + mAGrw_TREE003, + mAGrw_TREE004, + + mAGrw_TREE_STAGE_NUM +}; + +enum { + mAGrw_AROUND_TOP, + mAGrw_AROUND_BOTTOM, + mAGrw_AROUND_LEFT, + mAGrw_AROUND_RIGHT, + + mAGrw_AROUND_NUM +}; + +enum { + mAGrw_FLOWER_TIME, + mAGrw_NOT_FLOWER_TIME, + + mAGrw_FLOWER_TIME_NUM +}; + +enum { + mAGrw_TREE_TYPE_APPLE, + mAGrw_TREE_TYPE_CHESTNUT, // cherry tree + mAGrw_TREE_TYPE_PEAR, + mAGrw_TREE_TYPE_PEACH, + mAGrw_TREE_TYPE_ORANGE, + mAGrw_TREE_TYPE_NORMAL, + mAGrw_TREE_TYPE_MONEY, + mAGrw_TREE_TYPE_PALM, + mAGrw_TREE_TYPE_CEDAR, + mAGrw_TREE_TYPE_GOLD, + + mAGrw_TREE_TYPE_NUM +}; + +enum { + mAGrw_KILL_PALM_TREE, + mAGrw_KILL_CEDAR_TREE, + + mAGrw_KILL_TREE_NUM +}; + +enum { + mAGrw_CARP_UNCHANGED, + mAGrw_CARP_PLACE, + mAGrw_CARP_REMOVE, + + mAGrw_CARP_NUM +}; + +enum { + mAGrw_CHECK_CANCEL_12, + mAGrw_CHECK_CANCEL_32, + mAGrw_CHECK_CANCEL_22, + mAGrw_CHECK_CANCEL_36, + mAGrw_CHECK_CANCEL_LEFT_45, + mAGrw_CHECK_CANCEL_RIGHT_45, + mAGrw_CHECK_CANCEL_46, + mAGrw_CHECK_CANCEL_23, + mAGrw_CHECK_CANCEL_57, + mAGrw_CHECK_CANCEL_68, + mAGrw_CHECK_CANCEL_77, + + mAGrw_CHECK_CANCEL_NUM +}; + +typedef struct shine_stone_pos_info { + u8 block_x; + u8 block_z; + u8 ut_x; + u8 ut_z; +} mAGrw_SSPosInfo_c; + +typedef struct allgrow_s { + mAGrw_SSPosInfo_c shine_pos[TOTAL_PLAYER_NUM]; + mAGrw_SSPosInfo_c stone_pos[TOTAL_PLAYER_NUM]; +} mAGrw_AllGrow_c; + +typedef struct grow_info_s { + mFM_fg_c* around_block[mAGrw_AROUND_NUM]; + + int check_plant; + int past_days; + int block_height; + int ocean_row; + int flower_time; + int spoil_kabu; + + int block_x; + int block_z; + int ut_x; + int ut_z; + + int deposited_item; + int money_tree_num; + u8 fossil_record; + int fossil_num; + u8 honeycomb_tree_record; + u8 ftr_tree_record; + u8 money_stone_spawned; +} mAGrw_GrowInfo_c; + +typedef struct carp_block_info_s { + u8 signboard_in_block:1; + u8 carp_already_exists:1; + u8 villager_house_in_block:1; + u8 signboard_count:5; +} mAGrw_CarpBlockInfo_c; + +typedef struct carp_info_s { + mAGrw_CarpBlockInfo_c block_flags[FG_BLOCK_TOTAL_NUM]; + u8 signboard_blocks; + u8 carp_blocks; + u8 villager_house_blocks; +} mAGrw_CarpInfo_c; -extern void mAGrw_RenewalFgItem_ovl(lbRTC_time_c* time, int* haniwa_scheduled); extern void mAGrw_SearchDump(mFI_unit_c* dump_info); +extern void mAGrw_SetHideUtInfo(u16* hide, mActor_name_t* items); +extern void mAGrw_RenewalFgItem_ovl(lbRTC_time_c* time, int* haniwa_scheduled); #ifdef __cplusplus } diff --git a/include/m_collision_bg.h b/include/m_collision_bg.h index 919baf45..f6517ddb 100644 --- a/include/m_collision_bg.h +++ b/include/m_collision_bg.h @@ -43,6 +43,16 @@ enum background_attribute { mCoBG_ATTRIBUTE_SEA, }; +enum { + mCoBG_PLANT0 = 0, /* Stay a sapling */ + mCoBG_PLANT1 = 1, /* Grow until the first stage of growth */ + mCoBG_PLANT2 = 2, /* Grow until the second stage of growth */ + mCoBG_PLANT3 = 3, /* Grow until the third stage of growth */ + mCoBG_PLANT4 = 4, /* Fully grow */ + + mCoBG_KILL_PLANT = 7 /* No growth, all plants die on this unit */ +}; + /* sizeof(mCoBG_CollisionData_c) == 4*/ typedef struct collision_bg_data_s { /* 1------- -------- -------- -------- */ u32 shape:1; /* collision shape */ diff --git a/include/m_common_data.h b/include/m_common_data.h index b0833b34..6b6509cf 100644 --- a/include/m_common_data.h +++ b/include/m_common_data.h @@ -29,6 +29,7 @@ #include "m_npc_walk.h" #include "m_mask_cat.h" #include "m_npc_schedule_h.h" +#include "m_all_grow.h" #ifdef __cplusplus extern "C" { @@ -126,7 +127,8 @@ typedef struct Save_s { /* 0x022500 */ u8 _tmp7[0x22528 - 0x22500]; /* 0x022528 */ OSTime time_delta; /* time delta against GC RTC */ /* 0x022540 */ Island_c island; /* island data */ - /* 0x023E40 */ u8 _23E40[0x23F20 - 0x23E40]; + /* 0x023E40 */ mAGrw_AllGrow_c allgrow_ss_pos_info; + /* 0x023E68 */ u8 _23E68[0x23F20 - 0x23E68]; /* 0x023F20 */ MaskCat_c mask_cat; /* 0x024160 */ Anmret_c return_animal; /* information about villager which moved back in to your town after moving to someone else's town */ /* 0x02416C */ u8 _tmp10[0x24174 - 0x2416C]; diff --git a/include/m_field_info.h b/include/m_field_info.h index e35f80fb..9b76dd7f 100644 --- a/include/m_field_info.h +++ b/include/m_field_info.h @@ -154,6 +154,7 @@ extern int mFI_search_unit_around(xyz_t* wpos, mActor_name_t item); extern void mFI_BlockDepositOFF(u16* deposit, int ut_x, int ut_z); extern void mFI_PullTanukiPathTrees(); extern int mFI_CheckBlockKind_OR(int block_x, int block_z, u32 kind); +extern void mFI_GetIslandBlockNumX(int* island_block_x_nums); extern void mFI_PrintNowBGNum(gfxprint_t* gfxprint); extern void mFI_PrintFgAttr(gfxprint_t* gfxprint); diff --git a/include/m_field_make.h b/include/m_field_make.h index d5acc9e6..07372ea3 100644 --- a/include/m_field_make.h +++ b/include/m_field_make.h @@ -93,6 +93,7 @@ extern int* g_block_kind_p; extern void mFM_DecideBgTexIdx(u8* bg_tex_idx); extern void mFM_InitFgCombiSaveData(GAME* game); +extern mActor_name_t mFM_GetReserveName(int block_x, int block_z); #ifdef __cplusplus } diff --git a/include/m_home_h.h b/include/m_home_h.h index 4c9cd676..aa01123d 100644 --- a/include/m_home_h.h +++ b/include/m_home_h.h @@ -16,6 +16,7 @@ extern "C" { #define HOME_MAILBOX_SIZE 10 #define HANIWA_ITEM_HOLD_NUM 4 #define HANIWA_MESSAGE_LEN 128 +#define mHm_LAYER_NUM 4 enum { mHm_ROOM_MAIN, diff --git a/include/m_island.h b/include/m_island.h index 383fb7a8..0429b2ac 100644 --- a/include/m_island.h +++ b/include/m_island.h @@ -20,6 +20,8 @@ extern "C" { #define mISL_FG_BLOCK_X_NUM 2 #define mISL_FG_BLOCK_Z_NUM 1 +#define mISL_BLOCK_Z 8 + enum { mISL_ISLAND_BLOCK_LEFT, mISL_ISLAND_BLOCK_RIGHT, diff --git a/include/m_name_table.h b/include/m_name_table.h index 7608ace2..95d14867 100644 --- a/include/m_name_table.h +++ b/include/m_name_table.h @@ -52,7 +52,18 @@ enum { ITEM1_CAT_NUM }; +enum { + mNT_TREE_TYPE_NORMAL, + mNT_TREE_TYPE_PALM, + mNT_TREE_TYPE_CEDAR, + mNT_TREE_TYPE_GOLD, + + mNT_TREE_TYPE_NUM +}; + extern int mNT_check_unknown(mActor_name_t item_no); +extern int FGTreeType_check(mActor_name_t tree); +extern mActor_name_t bg_item_fg_sub_tree_grow(mActor_name_t tree, int past_days, int check_plant); /* Retrieve the item actor's category */ #define ITEM_NAME_GET_TYPE(n) (((n) & 0xF000) >> 12) @@ -71,6 +82,21 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define GET_NAME_ITEM1_CATEGORY(f) (((f) & 0x0F00) >> 8) #define IS_ITEM_FLOWER(item) ((item) >= FLOWER_LEAVES_PANSIES0 && (item) <= FLOWER_TULIP2) +#define IS_ITEM_ALIVE_TREE(item) \ + (((item) >= TREE_SAPLING && (item) <= TREE_30000BELLS) || \ + ((item) >= TREE_100BELLS_SAPLING && (item) <= TREE_PALM_FRUIT) || \ + ((item) >= CEDAR_TREE_SAPLING && (item) <= CEDAR_TREE) || \ + ((item) >= GOLD_TREE_SAPLING && (item) <= GOLD_TREE) \ + ) + +#define IS_ITEM_DEAD_SAPLING(item) \ + (((item) == DEAD_SAPLING) || \ + ((item) == DEAD_PALM_SAPLING) || \ + ((item) == DEAD_CEDAR_SAPLING) || \ + ((item) == DEAD_GOLD_SAPLING) \ + ) + +/* #define IS_ITEM_TREE(item) \ (((item) >= TREE_SAPLING && (item) <= TREE_30000BELLS) || \ ((item) >= TREE_100BELLS_SAPLING && (item) <= TREE_PALM_FRUIT) || \ @@ -81,6 +107,9 @@ extern int mNT_check_unknown(mActor_name_t item_no); ((item) == DEAD_CEDAR_SAPLING) || \ ((item) == DEAD_GOLD_SAPLING) \ ) +*/ + +#define IS_ITEM_TREE(item) (IS_ITEM_ALIVE_TREE(item) || IS_ITEM_DEAD_SAPLING(item)) #define IS_ITEM_GROWN_TREE(item) \ (((item) == TREE) || \ @@ -137,18 +166,30 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define KABU_NUM 4 #define EMPTY_NO 0x0000 - +#define TREE_STUMP001 (EMPTY_NO + 1) +#define TREE_STUMP002 (EMPTY_NO + 2) +#define TREE_STUMP003 (EMPTY_NO + 3) +#define TREE_STUMP004 (EMPTY_NO + 4) +#define FENCE0 (EMPTY_NO + 5) +#define FENCE1 (EMPTY_NO + 6) +#define MESSAGE_BOARD0 0x0007 #define GRASS_A 0x0008 #define GRASS_B (GRASS_A + 1) #define GRASS_C (GRASS_B + 1) +#define MESSAGE_BOARD1 0x000B +#define MAP_BOARD0 0x000C +#define MAP_BOARD1 0x000D +#define MUSIC_BOARD0 0x000E +#define MUSIC_BOARD1 0x000F #define BURIED_PITFALL0 0x002A +#define SHINE_SPOT 0x005C + #define TREE_BEES 0x005E #define TREE_FTR (TREE_BEES + 1) #define TREE_LIGHTS (TREE_FTR + 1) #define TREE_PRESENT (TREE_LIGHTS + 1) -#define TREE_BELLS 0x0069 #define ROCK_A 0x0063 #define ROCK_B (ROCK_A + 1) @@ -156,10 +197,35 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define ROCK_D (ROCK_C + 1) #define ROCK_E (ROCK_D + 1) +#define FLOWER_SEED 0x0068 +#define TREE_BELLS 0x0069 + +#define MONEY_ROCK_A 0x006A +#define MONEY_ROCK_B (MONEY_ROCK_A + 1) +#define MONEY_ROCK_C (MONEY_ROCK_B + 1) +#define MONEY_ROCK_D (MONEY_ROCK_C + 1) +#define MONEY_ROCK_E (MONEY_ROCK_D + 1) + +#define MONEY_FLOWER_SEED 0x006F + +#define TREE_PALM_STUMP001 (EMPTY_NO + 112) +#define TREE_PALM_STUMP002 (EMPTY_NO + 113) +#define TREE_PALM_STUMP003 (EMPTY_NO + 114) +#define TREE_PALM_STUMP004 (EMPTY_NO + 115) +#define CEDAR_TREE_STUMP001 (EMPTY_NO + 116) +#define CEDAR_TREE_STUMP002 (EMPTY_NO + 117) +#define CEDAR_TREE_STUMP003 (EMPTY_NO + 118) +#define CEDAR_TREE_STUMP004 (EMPTY_NO + 119) + #define CEDAR_TREE_BELLS 0x0078 #define CEDAR_TREE_FTR (CEDAR_TREE_BELLS + 1) #define CEDAR_TREE_BEES (CEDAR_TREE_FTR + 1) +#define GOLD_TREE_STUMP001 (EMPTY_NO + 123) +#define GOLD_TREE_STUMP002 (EMPTY_NO + 124) +#define GOLD_TREE_STUMP003 (EMPTY_NO + 125) +#define GOLD_TREE_STUMP004 (EMPTY_NO + 126) + #define GOLD_TREE_BELLS 0x007F #define GOLD_TREE_FTR (GOLD_TREE_BELLS + 1) #define GOLD_TREE_BEES (GOLD_TREE_FTR + 1) @@ -1036,7 +1102,7 @@ extern int mNT_check_unknown(mActor_name_t item_no); #define WATERFALL_SOUTH (POLICE_STATION + 1) #define WATERFALL_EAST (WATERFALL_SOUTH + 1) #define WATERFALL_WEST (WATERFALL_EAST + 1) -#define SIGN00 (WATERFALL_WEST + 1) +#define SIGN00 (STRUCTURE_START + 16) #define SIGN01 (SIGN00 + 1) #define SIGN02 (SIGN01 + 1) #define SIGN03 (SIGN02 + 1) diff --git a/include/m_shop.h b/include/m_shop.h index 8aa1ae43..f3095b7a 100644 --- a/include/m_shop.h +++ b/include/m_shop.h @@ -130,6 +130,7 @@ extern int mSP_GetShopLevel(); extern u32 mSP_ItemNo2ItemPrice(mActor_name_t item_no); extern int mSP_SearchItemCategoryPriority(mActor_name_t item_no, int category, int priority, GAME* unused); // not sure if it's actually a GAME* extern mActor_name_t mSP_RandomOneFossilSelect(int multi_fossil); +extern mActor_name_t mSP_RandomHaniwaSelect(mActor_name_t* item_buf, int num); extern void mItemDebug_ItemDebugMain(); extern void mItemDebug_ItemDebugDraw(gfxprint_t* gfxprint); diff --git a/include/m_snowman.h b/include/m_snowman.h index 5fbef453..c9e7400d 100644 --- a/include/m_snowman.h +++ b/include/m_snowman.h @@ -22,6 +22,9 @@ typedef struct snowman_save_data_s { /* 0x00 */ mSN_snowman_data_c snowmen_data[mSN_SAVE_COUNT]; } mSN_snowman_save_c; +extern int mSN_MeltSnowman(mActor_name_t* item, int past_days); +extern int mSN_ClearSnowman(mActor_name_t* item); + #ifdef __cplusplus } #endif diff --git a/rel/m_all_grow_ovl.c b/rel/m_all_grow_ovl.c new file mode 100644 index 00000000..b4ca1b74 --- /dev/null +++ b/rel/m_all_grow_ovl.c @@ -0,0 +1,3441 @@ +#include "m_all_grow.h" + +#include "libultra/libultra.h" +#include "m_common_data.h" +#include "m_name_table.h" +#include "m_island.h" +#include "m_collision_bg.h" +#include "m_snowman.h" +#include "m_home.h" +#include "m_house.h" +#include "m_snowman.h" +#include "m_shop.h" + +#ifdef MUST_MATCH +#include "ppcdis.h" +#endif + +static u8 l_candidate_num[FG_BLOCK_TOTAL_NUM]; + +static s8 l_non_area[mAGrw_CHECK_CANCEL_NUM][4] = { + /*x0 x1 z0 z1*/ + { 0, 0, -1, 0 }, + { -1, 1, -2, -1 }, + { -1, 0, -1, 0 }, + { -1, 1, -3, 2 }, + { -1, 2, -2, 2 }, + { -2, 1, -2, 2 }, + { -2, 1, -3, 2 }, + { -1, 0, -2, 0 }, + { -3, 1, -4, 2 }, + { -3, 2, -5, 2 }, + { -3, 3, -4, 2 } +}; + +typedef struct hide_area_s { + int x_ofs; + int z_ofs; +} mAGrw_HideArea_c; + +typedef struct hide_area_table_s { + int num; + mAGrw_HideArea_c* hide_p; +} mAGrw_HideAreaTable_c; + +static mAGrw_HideArea_c hide_3_2[1] = { + {0, -1} +}; + +static mAGrw_HideArea_c hide_2_2[2] = { + {-1, -1}, + {1, -1}, +}; + +static mAGrw_HideArea_c hide_3_6[2] = { + {-1, -2}, + {1, -2} +}; + +static mAGrw_HideArea_c hide_4_6[2] = { + {-2, -1}, + {1, -1} +}; + +static mAGrw_HideArea_c hide_2_3[2] = { + {-1, -2}, + {0, -2} +}; + +static mAGrw_HideArea_c hide_5_7[2] = { + {-3, -2}, + {1, -2} +}; + +static mAGrw_HideArea_c hide_6_8[2] = { + {-3, -2}, + {2, -2} +}; + +static mAGrw_HideArea_c hide_7_7[2] = { + {-3, -3}, + {3, -3} +}; + +static mAGrw_HideAreaTable_c l_hide_area_table[mAGrw_CHECK_CANCEL_NUM] = { + { 0, NULL }, + { 1, hide_3_2 }, + { 2, hide_2_2 }, + { 2, hide_3_6 }, + { 0, NULL }, + { 0, NULL }, + { 2, hide_4_6 }, + { 2, hide_2_3 }, + { 2, hide_5_7 }, + { 2, hide_6_8 }, + { 2, hide_7_7 }, +}; + +static mActor_name_t l_magrw_change_tree[3] = { + TREE, CEDAR_TREE, GOLD_TREE +}; + +static mActor_name_t l_magrw_bee_table[3] = { + TREE_BEES, CEDAR_TREE_BEES, GOLD_TREE_BEES +}; + +static mActor_name_t l_magrw_ftr_table[3] = { + TREE_FTR, CEDAR_TREE_FTR, GOLD_TREE_FTR +}; + +static mActor_name_t l_magrw_smn_table[3] = { + TREE_BELLS, CEDAR_TREE_BELLS, GOLD_TREE_BELLS +}; + +static void mAGrw_ClearSSPosInfo_com(mAGrw_SSPosInfo_c* pos_info) { + bzero(pos_info, sizeof(mAGrw_SSPosInfo_c)); +} + +static void mAGrw_ClearStonePosInfo(mAGrw_AllGrow_c* allgrow, int idx) { + if (idx >= 0 && idx < TOTAL_PLAYER_NUM) { + mAGrw_ClearSSPosInfo_com(&allgrow->stone_pos[idx]); + } +} + +static void mAGrw_ClearShinePosInfo(mAGrw_AllGrow_c* allgrow, int idx) { + if (idx >= 0 && idx < TOTAL_PLAYER_NUM) { + mAGrw_ClearSSPosInfo_com(&allgrow->shine_pos[idx]); + } +} + +static int mAGrw_CheckFreeSSPosInfo_com(mAGrw_SSPosInfo_c* ss_pos_info) { + int free = FALSE; + + if (ss_pos_info->block_x == 0 && ss_pos_info->block_z == 0) { + free = TRUE; + } + + return free; +} + +static mActor_name_t mAGrw_ToMoneyStone(mActor_name_t stone) { + mActor_name_t money_stone = stone - ROCK_A; + return money_stone + MONEY_ROCK_A; +} + +static mActor_name_t mAGrw_ToStone(mActor_name_t money_stone) { + mActor_name_t stone = money_stone - MONEY_ROCK_A; + return stone + ROCK_A; +} + +#define mAGrw_IsStone(item) \ + ((item) >= ROCK_A && (item) <= ROCK_E) + +#define mAGrw_IsMoneyStone(item) \ + (((item) >= MONEY_ROCK_A && (item) <= MONEY_ROCK_E) || (item) == MONEY_FLOWER_SEED) + +#define mAGrw_IsPosInfoGood(pos_info) \ + ((pos_info)->block_x != 0 && (pos_info)->block_x < FG_BLOCK_X_NUM + 1) && \ + ((pos_info)->block_z != 0 && (pos_info)->block_z < FG_BLOCK_Z_NUM + 1) && \ + ((pos_info)->ut_x < UT_X_NUM) && \ + ((pos_info)->ut_z < UT_Z_NUM) + +extern void mAGrw_ClearMoneyStoneShineGround() { + mFM_fg_c* block_items = Save_Get(fg[0]); + mActor_name_t* items; + mAGrw_AllGrow_c* allgrow = Save_GetPointer(allgrow_ss_pos_info); + int updated_money_stone = FALSE; + int updated_shine_spot = FALSE; + int acre; + int unit; + int player_no = Common_Get(player_no); + + for (acre = 0; acre < FG_BLOCK_TOTAL_NUM; acre++) { + items = block_items->items[0]; + + for (unit = 0; unit < UT_TOTAL_NUM; unit++) { + if (mAGrw_IsMoneyStone(*items)) { + *items = mAGrw_ToStone(*items); + updated_money_stone = TRUE; + } + else if (*items == SHINE_SPOT) { + *items = EMPTY_NO; + updated_shine_spot = TRUE; + } + + if (updated_money_stone == TRUE && updated_shine_spot == TRUE) { + acre = FG_BLOCK_TOTAL_NUM; + break; + } + + items++; + } + + block_items++; + } + + if (updated_money_stone == FALSE) { + mAGrw_ClearStonePosInfo(allgrow, player_no); + } + + if (updated_shine_spot == FALSE) { + mAGrw_ClearShinePosInfo(allgrow, player_no); + } +} + +extern void mAGrw_ClearAllShine_Stone() { + mFM_fg_c* block_items = Save_Get(fg[0]); + mActor_name_t* items; + int acre; + int unit; + + for (acre = 0; acre < FG_BLOCK_TOTAL_NUM; acre++) { + items = block_items->items[0]; + + for (unit = 0; unit < UT_TOTAL_NUM; unit++) { + if (mAGrw_IsMoneyStone(*items)) { + *items = mAGrw_ToStone(*items); + } + else if (*items == SHINE_SPOT) { + *items = EMPTY_NO; + } + + items++; + } + + block_items++; + } +} + +static void mAGrw_SetShineGround_player(mAGrw_AllGrow_c* allgrow, int player_no) { + if (player_no >= mPr_PLAYER_0 && player_no < mPr_PLAYER_NUM) { + mAGrw_SSPosInfo_c* player_ss_pos_info = &allgrow->shine_pos[player_no]; + + if (mAGrw_CheckFreeSSPosInfo_com(player_ss_pos_info) == FALSE) { + if (mAGrw_IsPosInfoGood(player_ss_pos_info)) { + int block_x = player_ss_pos_info->block_x - 1; + int block_z = player_ss_pos_info->block_z - 1; + mFM_fg_c* fg_block = &Save_Get(fg[block_z][block_x]); + mActor_name_t* item = &fg_block->items[player_ss_pos_info->ut_z][player_ss_pos_info->ut_x]; + + if (*item == EMPTY_NO) { + *item = SHINE_SPOT; + } + } + else { + mAGrw_ClearSSPosInfo_com(player_ss_pos_info); // invalid shine spot position + } + } + else { + mAGrw_ClearSSPosInfo_com(player_ss_pos_info); // Ensure it's cleared? + } + } +} + +static void mAGrw_SetMoneyStone_player(mAGrw_AllGrow_c* allgrow, int player_no) { + if (player_no >= mPr_PLAYER_0 && player_no < mPr_PLAYER_NUM) { + mAGrw_SSPosInfo_c* player_ss_pos_info = &allgrow->stone_pos[player_no]; + + if (mAGrw_CheckFreeSSPosInfo_com(player_ss_pos_info) == FALSE) { + if ( + (player_ss_pos_info->block_x != 0 && player_ss_pos_info->block_x < FG_BLOCK_X_NUM + 1) && + (player_ss_pos_info->block_z != 0 && player_ss_pos_info->block_z < FG_BLOCK_Z_NUM + 1) && + (player_ss_pos_info->ut_x < UT_X_NUM) && + (player_ss_pos_info->ut_z < UT_Z_NUM) + ) { + int block_x = player_ss_pos_info->block_x - 1; + int block_z = player_ss_pos_info->block_z - 1; + mFM_fg_c* fg_block = &Save_Get(fg[block_z][block_x]); + mActor_name_t* item = &fg_block->items[player_ss_pos_info->ut_z][player_ss_pos_info->ut_x]; + + if (!mAGrw_IsMoneyStone(*item) && (mAGrw_IsStone(*item) || mAGrw_IsMoneyStone(*item))) { + *item = mAGrw_ToMoneyStone(*item); + } + else if (!mAGrw_IsStone(*item) && !mAGrw_IsMoneyStone(*item)) { + mAGrw_ClearSSPosInfo_com(player_ss_pos_info); // not a stone at this location + } + } + else { + mAGrw_ClearSSPosInfo_com(player_ss_pos_info); // invalid shine spot position + } + } + else { + mAGrw_ClearSSPosInfo_com(player_ss_pos_info); // Ensure it's cleared? + } + } +} + +extern void mAGrw_RestoreStoneShine(int player_no) { + mAGrw_AllGrow_c* ss_pos_info = Save_GetPointer(allgrow_ss_pos_info); + if (player_no >= mPr_PLAYER_0 && player_no < mPr_PLAYER_NUM) { + mAGrw_SetMoneyStone_player(ss_pos_info, player_no); + mAGrw_SetShineGround_player(ss_pos_info, player_no); + } +} + +static int mAGrw_CheckMoneyStonePos(mAGrw_SSPosInfo_c* pos_info) { + int res = FALSE; + + if ( + mAGrw_CheckFreeSSPosInfo_com(pos_info) == FALSE && + mAGrw_IsPosInfoGood(pos_info) + ) { + int block_x = pos_info->block_x - 1; + int block_z = pos_info->block_z - 1; + mFM_fg_c* fg_block = &Save_Get(fg[block_z][block_x]); + mActor_name_t item = fg_block->items[pos_info->ut_z][pos_info->ut_x]; + + if ((item >= MONEY_ROCK_A && item <= MONEY_ROCK_E) || item == MONEY_FLOWER_SEED) { + res = TRUE; + } + } + + return res; +} + +static void mAGrw_ClearGrowInfo(mAGrw_GrowInfo_c* grow_info) { + bzero(grow_info, sizeof(mAGrw_GrowInfo_c)); +} + +static u8 mAGrw_GetTreeGrowCond(int ut_x, int ut_z) { + return (ut_x ^ ut_z) & 1; +} + +static void mAGrw_ClearAroundBlockInfo(mAGrw_GrowInfo_c* grow_info) { + mFM_fg_c** around_block = grow_info->around_block; + int i; + + for (i = 0; i < mAGrw_AROUND_NUM; i++) { + *around_block = NULL; + around_block++; + } +} + +static void mAGrw_SetAroundBlockInfo(mAGrw_GrowInfo_c* grow_info, int block_x, int block_z) { + mAGrw_ClearAroundBlockInfo(grow_info); + + if (block_x > 0) { + grow_info->around_block[mAGrw_AROUND_LEFT] = Save_GetPointer(fg[block_z][block_x - 1]); + } + + if (block_x < FG_BLOCK_X_NUM - 1) { + grow_info->around_block[mAGrw_AROUND_RIGHT] = Save_GetPointer(fg[block_z][block_x + 1]); + } + + if (block_z > 0) { + grow_info->around_block[mAGrw_AROUND_TOP] = Save_GetPointer(fg[block_z - 1][block_x]); + } + + if (block_z < FG_BLOCK_Z_NUM - 1) { + /* @BUG - should be fg[block_z + 1][block_x] */ + grow_info->around_block[mAGrw_AROUND_BOTTOM] = Save_GetPointer(fg[block_z + 1][block_z]); + } +} + +static void mAGrw_SetAroundBlockInfoIsland(mAGrw_GrowInfo_c* grow_info, int island_side) { + mAGrw_ClearAroundBlockInfo(grow_info); + + if (island_side == mISL_ISLAND_BLOCK_LEFT) { + grow_info->around_block[mAGrw_AROUND_RIGHT] = Save_GetPointer(island.fgblock[0][1]); + } + else if (island_side == mISL_ISLAND_BLOCK_RIGHT) { + grow_info->around_block[mAGrw_AROUND_LEFT] = Save_GetPointer(island.fgblock[0][0]); + } +} + +static lbRTC_day_t mAGrw_get_pastDays(lbRTC_time_c* now, lbRTC_time_c* last_grow_time) { + lbRTC_time_c temp; + int past_days; + + lbRTC_TimeCopy(&temp, last_grow_time); + + for (past_days = 0; past_days <= mAGrw_MAX_PAST_DAYS; past_days++) { + if (lbRTC_IsOverTime(now, &temp) == lbRTC_OVER) { + break; + } + + lbRTC_Add_DD(&temp, 1); + } + + return past_days; +} + +static int mAGrw_CheckSpoilKabuTime(lbRTC_time_c* grow_time, lbRTC_time_c* now) { + lbRTC_time_c temp; + int days = 0; + int spoil = FALSE; + + lbRTC_TimeCopy(&temp, grow_time); + + if (temp.weekday != lbRTC_SUNDAY && temp.weekday < lbRTC_WEEK) { + days = lbRTC_WEEK - temp.weekday; + } + + lbRTC_Add_DD(&temp, days); + + if (lbRTC_IsOverTime(&temp, now) == lbRTC_OVER) { + spoil = TRUE; + } + + return spoil; +} + +static int mAGrw_CheckFlowerTime(lbRTC_time_c* time) { + int res = mAGrw_NOT_FLOWER_TIME; + lbRTC_day_t day = time->day; + + if ( + (time->month == lbRTC_FEBRUARY && day >= 25) || + (time->month >= lbRTC_MARCH && time->month <= lbRTC_NOVEMBER) || + (time->month == lbRTC_DECEMBER && day < 10) + ) { + res = mAGrw_FLOWER_TIME; + } + + return res; +} + +static int aAGrw_GrowFlower(mActor_name_t* item) { + int res = FALSE; + + if (*item >= FLOWER_LEAVES_PANSIES0 && *item <= FLOWER_TULIP2) { + if (*item <= FLOWER_LEAVES_TULIP2) { + *item += (FLOWER_PANSIES0 - FLOWER_LEAVES_PANSIES0); + } + + res = TRUE; + } + + return res; +} + +static void mAGrw_GetUpUt(mActor_name_t** ut_p, mActor_name_t* ut, mFM_fg_c* around, int ut_x, int ut_z) { + if (ut_z > 0) { + *ut_p = ut - UT_Z_NUM; + } + else if (around != NULL) { + *ut_p = &around->items[UT_Z_NUM - 1][ut_x]; + } +} + +static void mAGrw_GetDownUt(mActor_name_t** ut_p, mActor_name_t* ut, mFM_fg_c* around, int ut_x, int ut_z) { + if (ut_z < UT_Z_NUM - 1) { + *ut_p = ut + UT_Z_NUM; + } + else if (around != NULL) { + *ut_p = &around->items[0][ut_x]; + } +} + +static void mAGrw_GetLeftUt(mActor_name_t** ut_p, mActor_name_t* ut, mFM_fg_c* around, int ut_x, int ut_z) { + if (ut_x > 0) { + *ut_p = ut - 1; + } + else if (around != NULL) { + *ut_p = &around->items[ut_z][UT_X_NUM - 1]; + } +} + +static void mAGrw_GetRightUt(mActor_name_t** ut_p, mActor_name_t* ut, mFM_fg_c* around, int ut_x, int ut_z) { + if (ut_x < UT_X_NUM - 1) { + *ut_p = ut + 1; + } + else if (around != NULL) { + *ut_p = &around->items[ut_z][0]; + } +} + +static void mAGrw_KillTree(mActor_name_t* tree) { + static mActor_name_t d_table[mNT_TREE_TYPE_NUM] = { + DEAD_SAPLING, + DEAD_PALM_SAPLING, + DEAD_CEDAR_SAPLING, + DEAD_GOLD_SAPLING + }; + + int type = FGTreeType_check(*tree); + + if (type < 0 || type >= mNT_TREE_TYPE_NUM) { + type = mNT_TREE_TYPE_NORMAL; + } + + *tree = d_table[type]; +} + +typedef void (*mAGrw_GET_NEAR_PROC)(mActor_name_t**, mActor_name_t*, mFM_fg_c*, int, int); + +static int mAGrw_CheckNearTree(mActor_name_t* item, mAGrw_GrowInfo_c* grow_info, int ut_x, int ut_z) { + static mAGrw_GET_NEAR_PROC get_near[mAGrw_AROUND_NUM] = { &mAGrw_GetUpUt, &mAGrw_GetDownUt, &mAGrw_GetLeftUt, &mAGrw_GetRightUt }; + + mActor_name_t* near; + int res = FALSE; + int i; + + if ( + *item == TREE_SAPLING || + *item == TREE_APPLE_SAPLING || + *item == TREE_ORANGE_SAPLING || + *item == TREE_PEACH_SAPLING || + *item == TREE_PEAR_SAPLING || + *item == TREE_CHERRY_SAPLING || + *item == TREE_1000BELLS_SAPLING || + *item == TREE_10000BELLS_SAPLING || + *item == TREE_30000BELLS_SAPLING || + *item == TREE_100BELLS_SAPLING || + *item == TREE_PALM_SAPLING || + *item == CEDAR_TREE_SAPLING || + *item == GOLD_TREE_SAPLING + ) { + if (mAGrw_GetTreeGrowCond(ut_x, ut_z) == TRUE) { + res = TRUE; + for (i = 0; i < mAGrw_AROUND_NUM; i++) { + near = NULL; + + (*get_near[i])(&near, item, grow_info->around_block[i], ut_x, ut_z); + + if (near != NULL) { + if ( + (*near >= TREE_SAPLING && *near <= TREE_30000BELLS) || + (*near >= TREE_100BELLS_SAPLING && *near <= TREE_PALM_FRUIT) || + (*near >= CEDAR_TREE_SAPLING && *near <= CEDAR_TREE) || + (*near >= GOLD_TREE_SAPLING && *near <= GOLD_TREE) || + (*near == TREE_BEES || *near == TREE_FTR || *near == TREE_LIGHTS || *near == TREE_PRESENT) || + (*near == TREE_BELLS) || + (*near == CEDAR_TREE_BELLS || *near == CEDAR_TREE_FTR || *near == CEDAR_TREE_BEES) || + (*near == GOLD_TREE_BELLS || *near == GOLD_TREE_FTR || *near == GOLD_TREE_BEES || *near == CEDAR_TREE_LIGHTS) || + (*near >= TREE_STUMP001 && *near <= TREE_STUMP004) || + (*near >= TREE_PALM_STUMP001 && *near <= TREE_PALM_STUMP004) || + (*near >= CEDAR_TREE_STUMP001 && *near <= CEDAR_TREE_STUMP004) || + (*near >= GOLD_TREE_STUMP001 && *near <= GOLD_TREE_STUMP004) + ) { + mAGrw_KillTree(item); + res = FALSE; + break; + } + } + } + } + else { + for (i = 0; i < mAGrw_AROUND_NUM; i++) { + near = NULL; + + (*get_near[i])(&near, item, grow_info->around_block[i], ut_x, ut_z); + + if (near != NULL) { + if ( + /* Trees */ + ((*near >= TREE_SAPLING && *near <= TREE_30000BELLS) || + (*near >= TREE_100BELLS_SAPLING && *near <= TREE_PALM_FRUIT) || + (*near >= CEDAR_TREE_SAPLING && *near <= CEDAR_TREE) || + (*near >= GOLD_TREE_SAPLING && *near <= GOLD_TREE) || + (*near == TREE_BEES || *near == TREE_FTR || *near == TREE_LIGHTS || *near == TREE_PRESENT || *near == TREE_BELLS) || + (*near == CEDAR_TREE_BELLS || *near == CEDAR_TREE_FTR || *near == CEDAR_TREE_BEES) || + (*near == CEDAR_TREE_LIGHTS) || + (*near == GOLD_TREE_BELLS || *near == GOLD_TREE_FTR || *near == GOLD_TREE_BEES)) && + /* Saplings */ + (*near != TREE_SAPLING && *near != TREE_APPLE_SAPLING && *near != TREE_ORANGE_SAPLING && *near != TREE_PEACH_SAPLING && *near != TREE_PEAR_SAPLING && *near != TREE_CHERRY_SAPLING && *near != TREE_1000BELLS_SAPLING && *near != TREE_10000BELLS_SAPLING && *near != TREE_30000BELLS_SAPLING && *near != TREE_100BELLS_SAPLING && *near != TREE_PALM_SAPLING && *near != CEDAR_TREE_SAPLING && *near != GOLD_TREE_SAPLING) || + /* Stumps */ + ((*near >= TREE_STUMP001 && *near <= TREE_STUMP004) || + (*near >= TREE_PALM_STUMP001 && *near <= TREE_PALM_STUMP004) || + (*near >= CEDAR_TREE_STUMP001 && *near <= CEDAR_TREE_STUMP004) || + (*near >= GOLD_TREE_STUMP001 && *near <= GOLD_TREE_STUMP004)) + ) { + mAGrw_KillTree(item); + } + } + } + + /* @BUG should be && */ + if ( + *item != DEAD_SAPLING || + *item != DEAD_PALM_SAPLING || + *item != DEAD_CEDAR_SAPLING || + *item != DEAD_GOLD_SAPLING + ) { + res = TRUE; + } + } + } + else { + res = TRUE; + } + + return res; +} + +static int mAGrw_CheckAppleTree(mActor_name_t item, int block_height, int ocean_row) { + int res = FALSE; + + if (item >= TREE_APPLE_SAPLING && item <= TREE_APPLE_FRUIT) { + res = TRUE; + } + + return res; +} + +static int mAGrw_CheckChestnutTree(mActor_name_t item, int block_height, int ocean_row) { + int res = FALSE; + + if (item >= TREE_CHERRY_SAPLING && item <= TREE_CHERRY_FRUIT) { + res = TRUE; + } + + return res; +} + +static int mAGrw_CheckPearTree(mActor_name_t item, int block_height, int ocean_row) { + int res = FALSE; + + if (item >= TREE_PEAR_SAPLING && item <= TREE_PEAR_FRUIT) { + res = TRUE; + } + + return res; +} + +static int mAGrw_CheckPeachTree(mActor_name_t item, int block_height, int ocean_row) { + int res = FALSE; + + if (item >= TREE_PEACH_SAPLING && item <= TREE_PEACH_FRUIT) { + res = TRUE; + } + + return res; +} + +static int mAGrw_CheckOrangeTree(mActor_name_t item, int block_height, int ocean_row) { + int res = FALSE; + + if (item >= TREE_ORANGE_SAPLING && item <= TREE_ORANGE_FRUIT) { + res = TRUE; + } + + return res; +} + +static int mAGrw_CheckNormalTree(mActor_name_t item, int block_height, int ocean_row) { + int res = FALSE; + + if (item >= TREE_SAPLING && item <= TREE) { + res = TRUE; + } + + return res; +} + +static int mAGrw_CheckMoney(mActor_name_t item, int block_height, int ocean_row) { + int res = FALSE; + + if ( + (item >= TREE_1000BELLS_SAPLING && item <= TREE_30000BELLS) || + (item >= TREE_100BELLS_SAPLING && item <= TREE_100BELLS) + ) { + res = TRUE; + } + + return res; +} + +static int mAGrw_CheckPalmTree(mActor_name_t item, int block_height, int ocean_row) { + int res = FALSE; + + if (ocean_row == TRUE && item >= TREE_PALM_SAPLING && item <= TREE_PALM_FRUIT) { + res = TRUE; + } + + return res; +} + +static int mAGrw_CheckCedarTree(mActor_name_t item, int block_height, int ocean_row) { + int res = FALSE; + + if (block_height >= 1 && item >= CEDAR_TREE_SAPLING && item <= CEDAR_TREE) { + res = TRUE; + } + + return res; +} + +static int mAGrw_CheckGoldTree(mActor_name_t item, int block_height, int ocean_row) { + int res = FALSE; + + /* @BUG - Should be item <= GOLD_TREE */ + if (item >= GOLD_TREE_SAPLING && item <= GOLD_TREE_SHOVEL) { + res = TRUE; + } + + return res; +} + +static int mAGrw_CheckKillPalmTree(mActor_name_t item, int block_height, int ocean_row) { + int res = FALSE; + + if (ocean_row == FALSE && item >= TREE_PALM_SAPLING && item <= TREE_PALM_FRUIT) { + res = TRUE; + } + + return res; +} + +static int mAGrw_CheckKillCedarTree(mActor_name_t item, int block_height, int ocean_row) { + int res = FALSE; + + if (block_height <= 0 && item >= CEDAR_TREE_SAPLING && item <= CEDAR_TREE) { + res = TRUE; + } + + return res; +} + +static void mAGrw_GrowTree_sub(mActor_name_t* item, int check_plant, int past_days) { + *item = bg_item_fg_sub_tree_grow(*item, past_days - 1, check_plant); +} + +typedef int (*mAGrw_CHECK_TREE_PROC)(mActor_name_t, int, int); + +static int mAGrw_GrowTree(mActor_name_t* item, mAGrw_GrowInfo_c* grow_info, int ut_x, int ut_z, int check_plant, int past_days, int block_height, int ocean_row) { + static mAGrw_CHECK_TREE_PROC check_tree_proc[mAGrw_TREE_TYPE_NUM] = { + &mAGrw_CheckAppleTree, + &mAGrw_CheckChestnutTree, + &mAGrw_CheckPearTree, + &mAGrw_CheckPeachTree, + &mAGrw_CheckOrangeTree, + &mAGrw_CheckNormalTree, + &mAGrw_CheckMoney, + &mAGrw_CheckPalmTree, + &mAGrw_CheckCedarTree, + &mAGrw_CheckGoldTree + }; + + static mAGrw_CHECK_TREE_PROC kill_tree_proc[mAGrw_KILL_TREE_NUM] = { + &mAGrw_CheckKillPalmTree, + &mAGrw_CheckKillCedarTree + }; + + int res = FALSE; + + if ( + (*item >= TREE_SAPLING && *item <= TREE_30000BELLS) || + (*item >= TREE_100BELLS_SAPLING && *item <= TREE_PALM_FRUIT) || + (*item >= CEDAR_TREE_SAPLING && *item <= CEDAR_TREE) || + (*item >= GOLD_TREE_SAPLING && *item <= GOLD_TREE) + ) { + if (mAGrw_CheckNearTree(item, grow_info, ut_x, ut_z) == TRUE) { + int i; + + for (i = 0; i < mAGrw_TREE_TYPE_NUM; i++) { + if ((*check_tree_proc[i])(*item, block_height, ocean_row) == TRUE) { + mAGrw_GrowTree_sub(item, check_plant, past_days); + break; + } + } + + if (i == mAGrw_TREE_TYPE_NUM) { + for (i = 0; i < mAGrw_KILL_TREE_NUM; i++) { + if ((*kill_tree_proc[i])(*item, block_height, ocean_row) == TRUE) { + mAGrw_KillTree(item); + break; + } + } + } + } + + res = TRUE; + } + + return res; +} + +static int mAGrw_GrowPlant_First(mActor_name_t* item, mAGrw_GrowInfo_c* grow_info) { + int res = FALSE; + + if (ITEM_NAME_GET_TYPE(*item) == NAME_TYPE_ITEM0 && ITEM_NAME_GET_CAT(*item) == ENV_CATEGORY && grow_info->check_plant != -1) { + res = aAGrw_GrowFlower(item); + } + + return res; +} + +static int mAGrw_GrowPlant(mActor_name_t* item, mAGrw_GrowInfo_c* grow_info) { + int res = FALSE; + + if (ITEM_NAME_GET_TYPE(*item) == NAME_TYPE_ITEM0) { + int category = ITEM_NAME_GET_CAT(*item); + + if (category == ENV_CATEGORY) { + switch (grow_info->check_plant) { + case -1: + { + *item = EMPTY_NO; + res = TRUE; + + break; + } + + case mCoBG_PLANT0: + { + res = aAGrw_GrowFlower(item); + + if (res == FALSE) { + if (IS_ITEM_ALIVE_TREE(*item)) { + mAGrw_KillTree(item); + res = TRUE; + } + else if (IS_ITEM_DEAD_SAPLING(*item)) { + *item = EMPTY_NO; /* Clear dead saplings */ + res = TRUE; + } + } + + break; + } + + default: + { + res = aAGrw_GrowFlower(item); + + if (res == FALSE) { + res = mAGrw_GrowTree( + item, + grow_info, + grow_info->ut_x, grow_info->ut_z, grow_info->check_plant, + grow_info->past_days, + grow_info->block_height, + grow_info->ocean_row + ); + + if (res == FALSE && IS_ITEM_DEAD_SAPLING(*item)) { + *item = EMPTY_NO; + res = TRUE; + } + } + break; + } + } + } + else if (IS_ITEM_GRASS(*item)) { + switch (grow_info->check_plant) { + case -1: + { + *item = EMPTY_NO; + break; + } + } + + res = TRUE; + } + } + + return res; +} + +static int mAGrw_MeltSnowman(mActor_name_t* item, mAGrw_GrowInfo_c* grow_info) { + return mSN_MeltSnowman(item, grow_info->past_days); +} + +static void mAGrw_MakeGrassTable(mActor_name_t* grass_table) { + static mActor_name_t base_grass_table[mAGrw_GRASS_TABLE_NUM] = { + GRASS_A, GRASS_A, GRASS_A, GRASS_A, + GRASS_B, GRASS_B, GRASS_B, GRASS_B, + GRASS_C, GRASS_C, GRASS_C, GRASS_C + }; + + int i; + + for (i = 0; i < mAGrw_GRASS_TABLE_NUM; i++) { + grass_table[i] = base_grass_table[i]; + } + + for (i = 0; i < 4; i++) { + int a = RANDOM(mAGrw_GRASS_TABLE_NUM); + int b = RANDOM(mAGrw_GRASS_TABLE_NUM); + mActor_name_t temp; + + temp = grass_table[a]; + grass_table[a] = grass_table[b]; + grass_table[b] = temp; + } +} + +static int mAGrw_SpoilKabu(mActor_name_t* item, mAGrw_GrowInfo_c* grow_info) { + int res = FALSE; + + if (ITEM_NAME_GET_TYPE(*item) == NAME_TYPE_ITEM1 && ITEM_NAME_GET_CAT(*item) == ITEM1_CAT_KABU) { + if (grow_info != NULL) { + if (grow_info->spoil_kabu == TRUE) { + *item = ITM_KABU_SPOILED; + } + } + else { + *item = ITM_KABU_SPOILED; + } + + res = TRUE; + } + + return res; +} + +static int mAGrw_ClearSpoiledKabu(mActor_name_t* item, mAGrw_GrowInfo_c* grow_info) { + int res = FALSE; + + if (*item == ITM_KABU_SPOILED) { + *item = EMPTY_NO; + res = TRUE; + } + + return res; +} + +static int mAGrw_ClearShineGround(mActor_name_t* item, mAGrw_GrowInfo_c* grow_info) { + int res = FALSE; + + if (*item == SHINE_SPOT) { + *item = EMPTY_NO; + res = TRUE; + } + + return res; +} + +static int mAGrw_RecordCheckItem(u8* record, mActor_name_t check_item, mActor_name_t* valid_items, int count, int block_x) { + int res = FALSE; + int i; + + for (i = 0; i < count; i++) { + if (check_item == *valid_items) { + *record |= (1 << block_x); + res = TRUE; + + break; + } + + valid_items++; + } + + return res; +} + +static int mAGrw_RecordHoneycombTree(mActor_name_t* item, mAGrw_GrowInfo_c* grow_info) { + return mAGrw_RecordCheckItem(&grow_info->honeycomb_tree_record, *item, l_magrw_bee_table, 3, grow_info->block_x); +} + +static int mAGrw_RecordFtrTree(mActor_name_t* item, mAGrw_GrowInfo_c* grow_info) { + return mAGrw_RecordCheckItem(&grow_info->ftr_tree_record, *item, l_magrw_ftr_table, 3, grow_info->block_x); +} + +static int mAGrw_RecordDepositFossil(mActor_name_t* item, mAGrw_GrowInfo_c* grow_info) { + int res = FALSE; + + if (grow_info->deposited_item == TRUE) { + res = mMsm_RecordDepositFossil(&grow_info->fossil_record, *item, grow_info->block_x); + + if (res == TRUE) { + grow_info->fossil_num++; + } + } + + return res; +} + +static int mAGrw_CheckChangeTree(mActor_name_t item) { + int res = FALSE; + int i; + + for (i = 0; i < 3; i++) { + if (item == l_magrw_change_tree[i]) { + res = TRUE; + + break; + } + } + + return res; +} + +static int mAGrw_CheckMoneyTree(mActor_name_t item) { + int res = FALSE; + int i; + + for (i = 0; i < 3; i++) { + if (item == l_magrw_smn_table[i]) { + res = TRUE; + + break; + } + } + + return res; +} + +static int mAGrw_CountMoneyTree(mActor_name_t* item, mAGrw_GrowInfo_c* grow_info) { + int res = FALSE; + + if (mAGrw_CheckMoneyTree(*item) == TRUE) { + grow_info->money_tree_num++; + res = TRUE; + } + + return res; +} + +static int mAGrw_CheckMoneyStone(mActor_name_t* item, mAGrw_GrowInfo_c* grow_info) { + int res = FALSE; + + if ((*item >= MONEY_ROCK_A && *item <= MONEY_ROCK_E) || *item == MONEY_FLOWER_SEED) { + grow_info->money_stone_spawned = TRUE; + res = TRUE; + } + + return res; +} + +static int mAGrw_GetChangeAbleTreeNum2(mActor_name_t* items) { + int num = 0; + + if (items != NULL) { + int i; + + for (i = 0; i < UT_TOTAL_NUM; i++) { + if (mAGrw_CheckChangeTree(*items) == TRUE) { + num++; + } + + items++; + } + } + + return num; +} + +static void mAGrw_ChangeItemBlock2(mActor_name_t* block_items, u8 changeable_num, mActor_name_t* target_table, mActor_name_t* source_table, int table_num) { + int changed = FALSE; + int selected = RANDOM(changeable_num); + int i; + int j; + + for (i = 0; i < UT_TOTAL_NUM; i++) { + for (j = 0; j < table_num; j++) { + if (*block_items == source_table[j]) { + if (selected <= 0) { + *block_items = target_table[j]; + changed = TRUE; + + break; + } + else { + selected--; + } + } + } + + if (changed) { + break; + } + + block_items++; + } +} + +static void mAGrw_SetTreeBlockLine(int block_x, mActor_name_t* target_table) { + u8 changeable_num[FG_BLOCK_Z_NUM]; + int possible_lines = 0; + int i; + + for (i = 0; i < FG_BLOCK_Z_NUM; i++) { + changeable_num[i] = mAGrw_GetChangeAbleTreeNum2(Save_Get(fg[i][block_x]).items[0]); + + if (changeable_num[i] != 0) { + possible_lines++; + } + } + + if (possible_lines > 0) { + int selected = RANDOM(possible_lines); + + for (i = 0; i < FG_BLOCK_Z_NUM; i++) { + if (changeable_num[i] != 0) { + if (selected == 0) { + mAGrw_ChangeItemBlock2(Save_Get(fg[i][block_x]).items[0], changeable_num[i], target_table, l_magrw_change_tree, 3); + break; + } + else { + selected--; + } + } + } + } +} + +static void mAGrw_SetHoneycombTree(u8 honeycomb_record) { + u8 block_num = mMsm_GetDepositBlockNum(honeycomb_record); + + if (block_num < FG_BLOCK_X_NUM) { + int i; + + for (i = 0; i < FG_BLOCK_X_NUM; i++) { + if (((honeycomb_record >> (i + 1)) & 1) == 0) { + mAGrw_SetTreeBlockLine(i, l_magrw_bee_table); + } + } + } +} + +static void mAGrw_SetFtrTree(u8 ftr_record) { + u8 block_num; + int selected; + int vacant_lines; + int n; + int i; + int j; + + block_num = mMsm_GetDepositBlockNum(ftr_record); + + if (block_num < mAGrw_FTR_TREE_NUM) { + vacant_lines = FG_BLOCK_X_NUM - block_num; + n = mAGrw_FTR_TREE_NUM - block_num; + + for (i = 0; i < n; i++) { + selected = RANDOM(vacant_lines); + + for (j = 0; j < FG_BLOCK_X_NUM; j++) { + if (((ftr_record >> (j + 1)) & 1) == 0) { + if (selected == 0) { + mAGrw_SetTreeBlockLine(j, l_magrw_ftr_table); + vacant_lines--; + ftr_record |= (1 << (j + 1)); + + break; + } + else { + selected--; + } + } + } + } + } +} + +static void mAGrw_SetMoneyTreeRandom(mFM_fg_c* fg_block, u8* changeable_num, u8* candidates) { + int selected = RANDOM(*candidates); + int i; + + for (i = 0; i < FG_BLOCK_TOTAL_NUM; i++) { + if (changeable_num[0] != 0) { + if (selected <= 0) { + mAGrw_ChangeItemBlock2(fg_block->items[0], changeable_num[0], l_magrw_smn_table, l_magrw_change_tree, 3); + changeable_num[0]--; + + if (changeable_num[0] == 0) { + candidates[0]--; + } + + break; + } + else { + selected--; + } + } + + fg_block++; + changeable_num++; + } +} + +static void mAGrw_SetMoneyTree(int moneytree_num) { + mFM_fg_c* fg_block = Save_Get(fg[0]); + u8* candidate_num = l_candidate_num; + u8 candidates = 0; + int total_candidate_num = 0; + int spawn_num; + int i; + + if (moneytree_num < mAGrw_MONEY_TREE_NUM) { + spawn_num = mAGrw_MONEY_TREE_NUM - moneytree_num; + bzero(candidate_num, FG_BLOCK_TOTAL_NUM * sizeof(u8)); + + for (i = 0; i < FG_BLOCK_TOTAL_NUM; i++) { + candidate_num[0] = mAGrw_GetChangeAbleTreeNum2(fg_block->items[0]); + + if (candidate_num[0] != 0) { + total_candidate_num += candidate_num[0]; + candidates++; + } + + candidate_num++; + fg_block++; + } + + if (total_candidate_num > 0) { + + if (spawn_num > total_candidate_num) { + spawn_num = total_candidate_num; + } + + for (spawn_num; spawn_num != 0; spawn_num--) { + mAGrw_SetMoneyTreeRandom(Save_Get(fg[0]), l_candidate_num, &candidates); + } + } + } +} + +static int mAGrw_CountNormalStone(mActor_name_t* block_items) { + int normal_stone = 0; + int i; + + if (block_items != NULL) { + for (i = 0; i < UT_TOTAL_NUM; i++) { + if (*block_items >= ROCK_A && *block_items <= ROCK_E) { + normal_stone++; + } + + block_items++; + } + } + + return normal_stone; +} + +static void mAGrw_SetMoneyStoneBlock(mAGrw_SSPosInfo_c* pos_info, mActor_name_t* items, u8 candidate_num) { + int selected = RANDOM(candidate_num); + int i; + + for (i = 0; i < UT_TOTAL_NUM; i++) { + if (*items >= ROCK_A && *items <= ROCK_E) { + if (selected <= 0) { + pos_info->ut_x = i % UT_X_NUM; + pos_info->ut_z = i / UT_X_NUM; + + break; + } + else { + selected--; + } + } + + items++; + } +} + +static void mAGrw_SetMoneyStone_com(mAGrw_SSPosInfo_c* pos_info, mActor_name_t* items) { + u8* candidate_num; + int selected_block; + u8 candidate_blocks = 0; + int total_spots = 0; + int i; + + candidate_num = l_candidate_num; + bzero(candidate_num, FG_BLOCK_TOTAL_NUM * sizeof(u8)); + + for (i = 0; i < FG_BLOCK_TOTAL_NUM; i++) { + *candidate_num = mAGrw_CountNormalStone(items); + + if (*candidate_num != 0) { + total_spots += candidate_num[0]; + candidate_blocks++; + } + + candidate_num++; + items += UT_TOTAL_NUM; + } + + items -= UT_TOTAL_NUM * FG_BLOCK_TOTAL_NUM; + + if (total_spots > 0) { + candidate_num = l_candidate_num; + selected_block = RANDOM(candidate_blocks); + + for (i = 0; i < FG_BLOCK_TOTAL_NUM; i++) { + if (candidate_num[0] != 0) { + if (selected_block <= 0) { + pos_info->block_x = 1 + (i % FG_BLOCK_X_NUM); + pos_info->block_z = 1 + (i / FG_BLOCK_X_NUM); + mAGrw_SetMoneyStoneBlock(pos_info, items, candidate_num[0]); + + break; + } + else { + selected_block--; + } + } + + candidate_num++; + items += UT_TOTAL_NUM; + } + } +} + +static void mAGrw_SetMoneyStone(mAGrw_AllGrow_c* all_grow, mActor_name_t* items) { + mAGrw_SSPosInfo_c* pos_info = all_grow->stone_pos; + int i; + + for (i = 0; i < TOTAL_PLAYER_NUM; i++) { + if ( + mAGrw_CheckFreeSSPosInfo_com(pos_info) == TRUE || + (Common_Get(player_no) == i && mAGrw_CheckMoneyStonePos(pos_info) == FALSE) + ) { + mAGrw_SetMoneyStone_com(pos_info, items); + } + + pos_info++; + } +} + +static void mAGrw_SetTree0Info(u16* tree0_info, mActor_name_t* items) { + int z; + int x; + + bzero(tree0_info, UT_Z_NUM * sizeof(u16)); + + for (z = 0; z < UT_Z_NUM; z++) { + for (x = 0; x < UT_X_NUM; x++) { + if ( + *items == TREE_SAPLING || + *items == TREE_APPLE_SAPLING || + *items == TREE_ORANGE_SAPLING || + *items == TREE_PEACH_SAPLING || + *items == TREE_PEAR_SAPLING || + *items == TREE_CHERRY_SAPLING || + *items == TREE_1000BELLS_SAPLING || + *items == TREE_10000BELLS_SAPLING || + *items == TREE_30000BELLS_SAPLING || + *items == TREE_100BELLS_SAPLING || + *items == TREE_PALM_SAPLING || + *items == CEDAR_TREE_SAPLING || + *items == GOLD_TREE_SAPLING + ) { + (*tree0_info) |= (1 << x); + } + + items++; + } + + tree0_info++; + } +} + +static void mAGrw_ResetTree0Info(u16* tree0_info, u8* normal_trees, u8* other_trees, mActor_name_t* items) { + int z; + int x; + + for (z = 0; z < UT_Z_NUM; z++) { + for (x = 0; x < UT_X_NUM; x++) { + if (((*tree0_info >> x) & 1) == 1) { + if ( + *items == DEAD_SAPLING || + *items == DEAD_PALM_SAPLING || + *items == DEAD_CEDAR_SAPLING || + *items == DEAD_GOLD_SAPLING + ) { + (*tree0_info) &= ~(1 << x); + } + else if ( + (*items >= TREE_SAPLING && *items <= TREE) || + (*items >= CEDAR_TREE_SAPLING && *items <= CEDAR_TREE) + ) { + normal_trees[0]++; + } + else if (*items != EMPTY_NO) { + other_trees[0]++; + } + } + + items++; + } + + tree0_info++; + } +} + +static void mAGrw_KillTree0(mActor_name_t* items, u16* tree0_info, int* normal_trees, int* other_trees) { + int selected_tree; + int is_normal_tree; + int kill_normal_tree = TRUE; + int* trees; + int z; + int x; + + if (*normal_trees > 0) { + trees = normal_trees; /* prefer to kill regular trees or cedar trees */ + } + else { + kill_normal_tree = FALSE; + trees = other_trees; + } + + selected_tree = RANDOM(*trees); + + for (z = 0; z < UT_Z_NUM; z++) { + for (x = 0; x < UT_X_NUM; x++) { + if (((*tree0_info >> x) & 1) == 1) { + is_normal_tree = (*items >= TREE_SAPLING && *items <= TREE) || (*items >= CEDAR_TREE_SAPLING && *items <= CEDAR_TREE); + + if (kill_normal_tree == is_normal_tree) { + if (selected_tree <= 0) { + tree0_info[0] &= ~(1 << x); /* remove the tree from the bitfield */ + mAGrw_KillTree(items); /* remove the tree item */ + trees[0]--; /* remove the tree from the 'other tree' count */ + z = UT_Z_NUM; /* break out of outer loop */ + + break; + } + else { + selected_tree--; + } + } + } + + items++; + } + + tree0_info++; + } +} + +static void mAGrw_ThinTree(mActor_name_t* items, u16* tree0_info, int normal_trees, int other_trees, int max_trees) { + u8 trees = 0; + u8 trees_in_acre; + int t_normal_trees; + int t_other_trees; + int i; + + for (i = 0; i < UT_TOTAL_NUM; i++) { + if ( + (*items >= TREE_SAPLING && *items <= TREE_30000BELLS) || + (*items >= TREE_100BELLS_SAPLING && *items <= TREE_PALM_FRUIT) || + (*items >= CEDAR_TREE_SAPLING && *items <= CEDAR_TREE) || + (*items >= GOLD_TREE_SAPLING && *items <= GOLD_TREE) || + (*items == TREE_BEES || *items == TREE_FTR || *items == TREE_LIGHTS || *items == TREE_PRESENT || *items == TREE_BELLS) || + (*items == CEDAR_TREE_BELLS || *items == CEDAR_TREE_FTR || *items == CEDAR_TREE_BEES || *items == CEDAR_TREE_LIGHTS) || + (*items == GOLD_TREE_BELLS || *items == GOLD_TREE_FTR || *items == GOLD_TREE_BEES) + ) { + trees++; + } + + items++; + } + + i = trees - max_trees; + if (i > 0) { + trees_in_acre = normal_trees + other_trees; + for (i; trees_in_acre != 0 && i != 0; i--, trees_in_acre--) { + mAGrw_KillTree0(items - UT_TOTAL_NUM, tree0_info, &normal_trees, &other_trees); + } + } +} + +static int mAGrw_CheckCarpTime(lbRTC_time_c* time) { + int carp_type = mAGrw_CARP_UNCHANGED; + + if (Common_Get(time.rtc_time.month) == lbRTC_MAY && Common_Get(time.rtc_time.day) <= 5) { + carp_type = mAGrw_CARP_PLACE; + } + else if (time->month == lbRTC_MAY && time->day <= 5) { + carp_type = mAGrw_CARP_REMOVE; + } + + return carp_type; +} + +static void mAGrw_SetCarpBlockInfo(mAGrw_CarpBlockInfo_c* block_info, mActor_name_t* items) { + int i; + + for (i = 0; i < UT_TOTAL_NUM; i++) { + if (*items >= SIGN00 && *items <= SIGN20) { + block_info->signboard_in_block = TRUE; + block_info->signboard_count++; + } + else if (*items == KOINOBORI_WINDSOCK) { + block_info->carp_already_exists = TRUE; + } + else if (*items >= NPC_HOUSE_START && *items < NPC_HOUSE_END) { + block_info->villager_house_in_block = TRUE; + } + + items++; + } +} + +static void mAGrw_SetCarpInfo(mAGrw_CarpInfo_c* carp_info, mFM_fg_c* fg_block) { + mAGrw_CarpBlockInfo_c* block_info = carp_info->block_flags; + int i; + + for (i = 0; i < FG_BLOCK_TOTAL_NUM; i++) { + mAGrw_SetCarpBlockInfo(block_info, fg_block->items[0]); + + if (block_info->carp_already_exists == TRUE) { + carp_info->carp_blocks++; + block_info->signboard_in_block = FALSE; + } + else if (block_info->signboard_in_block == TRUE) { + carp_info->signboard_blocks++; + } + + if (block_info->villager_house_in_block == TRUE) { + carp_info->villager_house_blocks++; + } + + block_info++; + fg_block++; + } +} + +static void mAGrw_SetCarpBlock(mActor_name_t* items, int signboard_count) { + if (signboard_count > 0 && items != NULL) { + int selected = RANDOM(signboard_count); + int i; + + for (i = 0; i < UT_TOTAL_NUM; i++) { + if (*items >= SIGN00 && *items <= SIGN20) { + if (selected <= 0) { + *items = KOINOBORI_WINDSOCK; + + break; + } + else { + selected--; + } + } + + items++; + } + } +} + +static void mAGrw_ClearCarpBlock(mActor_name_t* items, int block_x, int block_z) { + int i; + + for (i = 0; i < UT_TOTAL_NUM; i++) { + if (*items == KOINOBORI_WINDSOCK) { + *items = mFM_GetReseveName(block_x, block_z); + } + + items++; + } +} + +static void mAGrw_KeepReserve(mAGrw_CarpInfo_c* carp_info, mFM_fg_c* fg_blocks) { + u8 valid_signboard_map[FG_BLOCK_Z_NUM]; + mAGrw_CarpBlockInfo_c* block_info; + mFM_fg_c* fg_block_p = fg_blocks; + int selected; + int blocks; + int bx; + int bz; + u8* map_p; + u8 can_have_villager_house; + int j; + int i; + int valid; + int temp; + + if (carp_info->signboard_blocks < 3) { + for (blocks = 3 - carp_info->signboard_blocks; blocks != 0 && carp_info->carp_blocks != 0; blocks--) { + block_info = carp_info->block_flags; + fg_blocks = fg_block_p; + selected = RANDOM(carp_info->carp_blocks); + + for (bz = 0; bz < FG_BLOCK_Z_NUM; bz++) { + for (bx = 0; bx < FG_BLOCK_X_NUM; bx++) { + if (block_info->carp_already_exists == TRUE) { + if (selected <= 0) { + mAGrw_ClearCarpBlock(fg_blocks->items[0], bx + 1, bz + 1); + block_info->carp_already_exists = FALSE; + carp_info->carp_blocks--; + + bz = FG_BLOCK_Z_NUM; + break; + } + else { + selected--; + } + } + + fg_blocks++; + block_info++; + } + } + } + } + else if (carp_info->carp_blocks < 5) { + can_have_villager_house = FALSE; + i = 3; + while (carp_info->signboard_blocks != 0 && i != 0) { + for (j = 1; j <= 3; j++) { + map_p = valid_signboard_map; + valid = 0; + + bzero(valid_signboard_map, FG_BLOCK_Z_NUM * sizeof(u8)); + block_info = carp_info->block_flags; + + for (bz = 0; bz < FG_BLOCK_Z_NUM; bz++) { + for (bx = 0; bx < FG_BLOCK_X_NUM; bx++) { + if ( + block_info->signboard_in_block == TRUE && + block_info->villager_house_in_block == can_have_villager_house && + block_info->signboard_count == j + ) { + valid++; + map_p[0] |= (1 << bx); + } + + block_info++; + } + + map_p++; + } + + if (valid > i) { + temp = i; + } + else { + temp = valid; + } + + /* Place koinobori windsocks */ + while (temp != 0 && valid != 0) { + selected = RANDOM(valid); + map_p = valid_signboard_map; + block_info = carp_info->block_flags; + + for (bz = 0; bz < FG_BLOCK_Z_NUM; bz++) { + for (bx = 0; bx < FG_BLOCK_X_NUM; bx++) { + if (((map_p[0] >> bx) & 1) == 1) { + if (selected <= 0) { + block_info->signboard_in_block = FALSE; + bz = 6; + valid--; + i--; + carp_info->signboard_blocks--; + map_p[0] &= ~(1 << bx); /* clear signboard in valid map */ + + break; + } + else { + selected--; + } + } + + block_info++; + } + + map_p++; + } + + temp--; + } + } + + can_have_villager_house ^= TRUE; + } + } +} + +static void mAGrw_SetCarpOnHomeBlock(mAGrw_CarpInfo_c* carp_info, mFM_fg_c* fg_block, int count) { + u8 block_house_info[2]; + mAGrw_CarpBlockInfo_c* block_info; + mFM_fg_c* fg_block_p = fg_block; + u8 spawn_on_home_block = TRUE; + int selected; + int i; + + bzero(block_house_info, 2 * sizeof(u8)); + + block_info = carp_info->block_flags; + for (i = 0; i < FG_BLOCK_TOTAL_NUM; i++) { + if (block_info->signboard_in_block == TRUE) { + if (block_info->villager_house_in_block == TRUE) { + block_house_info[1]++; + } + else { + block_house_info[0]++; + } + } + + block_info++; + } + + while (count != 0 && carp_info->signboard_blocks != 0) { + while (block_house_info[spawn_on_home_block] != 0 && count != 0) { + block_info = carp_info->block_flags; + fg_block = fg_block_p; + selected = RANDOM(block_house_info[spawn_on_home_block]); + + for (i = 0; i < FG_BLOCK_TOTAL_NUM; i++) { + if (block_info->signboard_in_block == TRUE && block_info->villager_house_in_block == spawn_on_home_block) { + if (selected <= 0) { + mAGrw_SetCarpBlock(fg_block->items[0], block_info->signboard_count); + count--; + + block_info->signboard_in_block = FALSE; + carp_info->signboard_blocks--; + + block_info->carp_already_exists = TRUE; + carp_info->carp_blocks++; + + block_house_info[spawn_on_home_block]--; + + break; + } + else { + selected--; + } + } + + fg_block++; + block_info++; + } + } + + if (block_house_info[0] == 0 && block_house_info[1] == 0) { + break; + } + + spawn_on_home_block ^= TRUE; + } +} + +static void mAGrw_SetEnoughCarp(mAGrw_CarpInfo_c* carp_info, mFM_fg_c* fg_block) { + mAGrw_KeepReserve(carp_info, fg_block); + + if (carp_info->signboard_blocks > 3 && carp_info->carp_blocks < 5) { + int count = 5 - carp_info->carp_blocks; + int signboard_blocks = carp_info->signboard_blocks - 3; + + if (count > signboard_blocks) { + count = signboard_blocks; + } + + if (count > 0) { + mAGrw_SetCarpOnHomeBlock(carp_info, fg_block, count); + } + } +} + +static void mAGrw_ClearAllCarp(mFM_fg_c* fg_block) { + int bz; + int bx; + + for (bz = 0; bz < FG_BLOCK_Z_NUM; bz++) { + for (bx = 0; bx < FG_BLOCK_X_NUM; bx++) { + mAGrw_ClearCarpBlock(fg_block->items[0], bx + 1, bz + 1); + fg_block++; + } + } +} + +static void mAGrw_SetCarp(lbRTC_time_c* time) { + mAGrw_CarpInfo_c carp_info; + int carp_state = mAGrw_CheckCarpTime(time); + mFM_fg_c* fg_block = Save_Get(fg[0]); + + if (carp_state == mAGrw_CARP_PLACE || carp_state == mAGrw_CARP_REMOVE) { + if (carp_state == mAGrw_CARP_PLACE) { + bzero(&carp_info, sizeof(mAGrw_CarpInfo_c)); + mAGrw_SetCarpInfo(&carp_info, fg_block); + mAGrw_SetEnoughCarp(&carp_info, fg_block); + } + else { + mAGrw_ClearAllCarp(fg_block); + } + } +} + +typedef int (*mAGrw_GROW_PROC)(mActor_name_t*, mAGrw_GrowInfo_c*); + +static void mAGrw_GrowBlockFgItem(mActor_name_t* items, mCoBG_Collision_u* col, u16* deposit, mAGrw_GrowInfo_c* grow_info, int proc_type) { + static mAGrw_GROW_PROC first_grow_proc[] = { + &mAGrw_GrowPlant_First, + &mAGrw_ClearShineGround, + &mAGrw_RecordHoneycombTree, + &mAGrw_RecordFtrTree, + &mAGrw_RecordDepositFossil, + &mAGrw_CountMoneyTree, + &mAGrw_CheckMoneyStone, + &mAGrw_MeltSnowman + }; + + static mAGrw_GROW_PROC grow_proc[] = { + &mAGrw_ClearSpoiledKabu, + &mAGrw_SpoilKabu, + &mAGrw_GrowPlant, + &mAGrw_MeltSnowman, + &mAGrw_ClearShineGround, + &mAGrw_RecordHoneycombTree, + &mAGrw_RecordFtrTree, + &mAGrw_RecordDepositFossil, + &mAGrw_CountMoneyTree, + &mAGrw_CheckMoneyStone + }; + + static mAGrw_GROW_PROC first_island_proc[] = { + &mAGrw_GrowPlant_First + }; + + static mAGrw_GROW_PROC grow_island_proc[] = { + &mAGrw_ClearSpoiledKabu, + &mAGrw_SpoilKabu, + &mAGrw_GrowPlant + }; + + static mAGrw_GROW_PROC* grow_proc_table[mAGrw_GROW_NUM] = { + first_grow_proc, + grow_proc, + first_grow_proc, + first_island_proc, + grow_island_proc, + first_island_proc + }; + + static int proc_max_table[mAGrw_GROW_NUM] = { 8, 10, 8, 1, 3, 1 }; + + xyz_t t_wpos = {0.0f, 0.0f, 0.0f}; + xyz_t wpos = {0.0f, 0.0f, 0.0f}; + + mAGrw_GROW_PROC* proc_table; + int proc_table_num; + int ut_z; + int ut_x; + int i; + + mFI_BkNum2WposXZ(&wpos.x, &wpos.z, grow_info->block_x, grow_info->block_z); + wpos.x += mFI_UT_WORLDSIZE_X_F / 2.0f; + wpos.z += mFI_UT_WORLDSIZE_Z_F / 2.0f; + + t_wpos = wpos; + proc_table = grow_proc_table[proc_type]; + proc_table_num = proc_max_table[proc_type]; + + for (ut_z = 0; ut_z < UT_Z_NUM; ut_z++) { + t_wpos.x = wpos.x; + + for (ut_x = 0; ut_x < UT_X_NUM; ut_x++) { + grow_info->deposited_item = mFI_GetLineDeposit(deposit, ut_x); + grow_info->ut_x = ut_x; + grow_info->ut_z = ut_z; + grow_info->check_plant = mCoBG_Attribute2CheckPlant(col->data.unit_attribute, &t_wpos); + grow_info->block_height = mCoBG_GetLayer(&t_wpos); + + for (i = 0; i < proc_table_num; i++) { + if ((*proc_table[i])(items, grow_info) == TRUE) { + break; + } + } + + items++; + col++; + t_wpos.x += mFI_UT_WORLDSIZE_X_F; + } + + deposit++; + t_wpos.z += mFI_UT_WORLDSIZE_Z_F; + } +} + +static void mAGrw_GrowFieldFgItem(lbRTC_time_c* now_time, lbRTC_time_c* grow_time, int flower_time, int spoil_kabu, u8* fossil_record, int* fossil_num, int proc_type) { + static u16 tree0_info[UT_Z_NUM]; + + mAGrw_GrowInfo_c grow_info; + mCoBG_Collision_u* col; + mFM_fg_c* fg_block; + u8 normal_trees; + u8 other_trees; + int bz; + int bx; + + fg_block = Save_Get(fg[0]); + mAGrw_ClearGrowInfo(&grow_info); + grow_info.spoil_kabu = spoil_kabu; + + if (proc_type == mAGrw_GROW) { + grow_info.past_days = mAGrw_get_pastDays(now_time, grow_time); + } + else if (proc_type == mAGrw_GROW_FIRST_FORCE) { + if (now_time->day != Save_Get(all_grow_renew_time).day) { + grow_info.past_days = -1; + } + else { + grow_info.past_days = 0; + } + } + + grow_info.flower_time = flower_time; + + for (bz = 0; bz < FG_BLOCK_Z_NUM; bz++) { + for (bx = 0; bx < FG_BLOCK_X_NUM; bx++) { + normal_trees = 0; + other_trees = 0; + + mAGrw_SetTree0Info(tree0_info, fg_block->items[0]); + grow_info.block_x = bx + 1; + grow_info.block_z = bz + 1; + + if (bz + 1 == FG_BLOCK_Z_NUM) { + grow_info.ocean_row = TRUE; + } + else { + grow_info.ocean_row = FALSE; + } + + col = mFI_GetBkNum2ColTop(grow_info.block_x, grow_info.block_z); + + if (col != NULL) { + if (proc_type == mAGrw_GROW) { + mAGrw_SetAroundBlockInfo(&grow_info, bx, bz); + } + + mAGrw_GrowBlockFgItem(fg_block->items[0], col, Save_Get(deposit[bx + bz * FG_BLOCK_X_NUM]), &grow_info, proc_type); + } + + mAGrw_ResetTree0Info(tree0_info, &normal_trees, &other_trees, fg_block->items[0]); + mAGrw_ThinTree(fg_block->items[0], tree0_info, normal_trees, other_trees, mAGrw_MAX_TREES_PER_BLOCK); + + fg_block++; + } + } + + *fossil_record = grow_info.fossil_record; + *fossil_num = grow_info.fossil_num; + + mAGrw_SetHoneycombTree(grow_info.honeycomb_tree_record); + mAGrw_SetFtrTree(grow_info.ftr_tree_record); + mAGrw_SetMoneyTree(grow_info.money_tree_num); +} + +static int mAGrw_CheckTree000(mActor_name_t item) { + return item == TREE_SAPLING || + item == TREE_APPLE_SAPLING || + item == TREE_ORANGE_SAPLING || + item == TREE_PEACH_SAPLING || + item == TREE_PEAR_SAPLING || + item == TREE_CHERRY_SAPLING || + item == TREE_1000BELLS_SAPLING || + item == TREE_10000BELLS_SAPLING || + item == TREE_30000BELLS_SAPLING || + item == TREE_100BELLS_SAPLING || + item == TREE_PALM_SAPLING || + item == CEDAR_TREE_SAPLING || + item == GOLD_TREE_SAPLING; +} + +static mAGrw_CheckTree001(mActor_name_t item) { + return item == TREE_S0 || + item == TREE_APPLE_S0 || + item == TREE_ORANGE_S0 || + item == TREE_PEACH_S0 || + item == TREE_PEAR_S0 || + item == TREE_CHERRY_S0 || + item == TREE_1000BELLS_S0 || + item == TREE_10000BELLS_S0 || + item == TREE_30000BELLS_S0 || + item == TREE_1000BELLS_S0 || + item == TREE_10000BELLS_S0 || + item == TREE_30000BELLS_S0 || + item == TREE_100BELLS_S0 || + item == TREE_PALM_S0 || + item == CEDAR_TREE_S0 || + item == GOLD_TREE_S0; +} + +static mAGrw_CheckTree002(mActor_name_t item) { + return item == TREE_S1 || + item == TREE_APPLE_S1 || + item == TREE_ORANGE_S1 || + item == TREE_PEACH_S1 || + item == TREE_PEAR_S1 || + item == TREE_CHERRY_S1 || + item == TREE_1000BELLS_S1 || + item == TREE_10000BELLS_S1 || + item == TREE_30000BELLS_S1 || + item == TREE_1000BELLS_S1 || + item == TREE_10000BELLS_S1 || + item == TREE_30000BELLS_S1 || + item == TREE_100BELLS_S1 || + item == TREE_PALM_S1 || + item == CEDAR_TREE_S1 || + item == GOLD_TREE_S1; +} + +static mAGrw_CheckTree003(mActor_name_t item) { + return item == TREE_S2 || + item == TREE_APPLE_S2 || + item == TREE_ORANGE_S2 || + item == TREE_PEACH_S2 || + item == TREE_PEAR_S2 || + item == TREE_CHERRY_S2 || + item == TREE_1000BELLS_S2 || + item == TREE_10000BELLS_S2 || + item == TREE_30000BELLS_S2 || + item == TREE_1000BELLS_S2 || + item == TREE_10000BELLS_S2 || + item == TREE_30000BELLS_S2 || + item == TREE_100BELLS_S2 || + item == TREE_PALM_S2 || + item == CEDAR_TREE_S2 || + item == GOLD_TREE_S2; +} + +static mAGrw_CheckTree004(mActor_name_t item) { + return item == TREE || item == TREE_APPLE_FRUIT || item == TREE_ORANGE_FRUIT || item == TREE_PEACH_FRUIT || item == TREE_PEAR_FRUIT || item == TREE_CHERRY_FRUIT || + item == TREE_1000BELLS || item == TREE_10000BELLS || item == TREE_30000BELLS || item == TREE_100BELLS || + item == TREE_PALM_FRUIT || + item == CEDAR_TREE || + item == GOLD_TREE || item == GOLD_TREE_SHOVEL || + item == TREE_APPLE_NOFRUIT_0 || item == TREE_ORANGE_NOFRUIT_0 || item == TREE_PEACH_NOFRUIT_0 || item == TREE_PEAR_NOFRUIT_0 || item == TREE_CHERRY_NOFRUIT_0 || item == TREE_PALM_NOFRUIT_0 || + item == TREE_APPLE_NOFRUIT_1 || item == TREE_ORANGE_NOFRUIT_1 || item == TREE_PEACH_NOFRUIT_1 || item == TREE_PEAR_NOFRUIT_1 || item == TREE_CHERRY_NOFRUIT_1 || item == TREE_PALM_NOFRUIT_1 || + item == TREE_APPLE_NOFRUIT_2 || item == TREE_ORANGE_NOFRUIT_2 || item == TREE_PEACH_NOFRUIT_2 || item == TREE_PEAR_NOFRUIT_2 || item == TREE_CHERRY_NOFRUIT_2 || item == TREE_PALM_NOFRUIT_2 || + item == TREE_BEES || item == TREE_FTR || item == TREE_LIGHTS || item == TREE_PRESENT || item == TREE_BELLS || + item == CEDAR_TREE_BELLS || item == CEDAR_TREE_FTR || item == CEDAR_TREE_BEES || item == CEDAR_TREE_LIGHTS || + item == GOLD_TREE_BELLS || item == GOLD_TREE_FTR || item == GOLD_TREE_BEES; +} + +typedef int (*mAGrw_CHECK_FG_PROC)(mActor_name_t); + +static int mAGrw_CheckTree000(mActor_name_t); +static int mAGrw_CheckTree001(mActor_name_t); +static int mAGrw_CheckTree002(mActor_name_t); +static int mAGrw_CheckTree003(mActor_name_t); +static int mAGrw_CheckTree004(mActor_name_t); + +typedef int (*mAGrw_CHECK_FG_PROC)(mActor_name_t); + +static void mAGrw_LimitTreeLineIsland(mFM_fg_c* island_block) { + static mAGrw_CHECK_FG_PROC check_fg[mAGrw_TREE_STAGE_NUM] = { + &mAGrw_CheckTree000, + &mAGrw_CheckTree001, + &mAGrw_CheckTree002, + &mAGrw_CheckTree003, + &mAGrw_CheckTree004 + }; + + int tree_size_count_tbl[mAGrw_TREE_STAGE_NUM]; + mFM_fg_c* island_block_p; + u8 ignored_record; + int max_trees; + int selected; + int ut_x; + int ut_z; + mActor_name_t* items; + int trees; + int tree_size; + int block; + + island_block_p = island_block; + + for (ut_z = 0; ut_z < UT_Z_NUM; ut_z++) { + bzero(tree_size_count_tbl, sizeof(int) * mAGrw_TREE_STAGE_NUM); + island_block = island_block_p; + trees = 0; + ignored_record = 0; + + /* Count all trees and log size of each tree */ + for (block = 0; block < mISL_FG_BLOCK_X_NUM; block++) { + items = island_block->items[ut_z]; + for (ut_x = 0; ut_x < UT_X_NUM; ut_x++) { + for (tree_size = 0; tree_size < mAGrw_TREE_STAGE_NUM; tree_size++) { + if ((*check_fg[tree_size])(*items) == TRUE) { + tree_size_count_tbl[tree_size]++; + trees++; + + break; + } + } + + items++; + } + + island_block++; + } + + /* Check and do trimming */ + if (trees > mAGrw_ISL_TREE_MAX_LINE) { + max_trees = trees - mAGrw_ISL_TREE_MAX_LINE; + + for (tree_size = 0; tree_size < mAGrw_TREE_STAGE_NUM; tree_size++) { + island_block = island_block_p; + if (max_trees < tree_size_count_tbl[tree_size]) { + break; + } + + for (block = 0; block < mISL_FG_BLOCK_X_NUM; block++) { + items = island_block->items[ut_z]; + for (ut_x = 0; ut_x < UT_X_NUM; ut_x++) { + if ((*check_fg[tree_size])(*items) == TRUE) { + mAGrw_KillTree(items); + } + + items++; + } + + island_block++; + } + + ignored_record |= (1 << tree_size); + max_trees -= tree_size_count_tbl[tree_size]; + tree_size_count_tbl[tree_size] = 0; + + if (max_trees == 0) { + break; + } + } + + tree_size = 0; + + while (max_trees > 0) { + if (((ignored_record >> tree_size) & 1) == 0 && tree_size_count_tbl[tree_size] > 0) { + island_block = island_block_p; + selected = RANDOM(tree_size_count_tbl[tree_size]); + + for (block = 0; block < mISL_FG_BLOCK_X_NUM; block++) { + items = island_block->items[ut_z]; + for (ut_x = 0; ut_x < UT_X_NUM; ut_x++) { + if ((*check_fg[tree_size])(*items) == TRUE) { + if (selected == 0) { + mAGrw_KillTree(items); + block = mISL_FG_BLOCK_X_NUM; + + break; + } + else { + selected--; + } + } + + items++; + } + + island_block++; + } + + tree_size_count_tbl[tree_size]--; + max_trees--; + } + else { + tree_size++; + } + + if (tree_size >= mAGrw_TREE_STAGE_NUM) { + break; + } + } + } + } +} + +static void mAGr_GrowIslandFgItem(lbRTC_time_c* now_time, lbRTC_time_c* grow_time, int flower_time, int spoil_kabu, int proc_type) { + static u16 tree0_info[UT_Z_NUM]; + + mAGrw_GrowInfo_c grow_info; + int island_block_x_nums[mISL_FG_BLOCK_X_NUM]; + mFM_fg_c* island_block = Save_Get(island).fgblock[0]; + mCoBG_Collision_u* col; + int bx; + + mAGrw_ClearGrowInfo(&grow_info); + grow_info.spoil_kabu = spoil_kabu; + + if (proc_type == mAGrw_GROW) { + grow_info.past_days = mAGrw_get_pastDays(now_time, grow_time); + } + else if (proc_type == mAGrw_GROW_FIRST_FORCE) { + if (now_time->day != Save_Get(all_grow_renew_time).day) { + grow_info.past_days = -1; + } + else { + grow_info.past_days = 0; + } + } + + grow_info.flower_time = flower_time; + mFI_GetIslandBlockNumX(island_block_x_nums); + grow_info.ocean_row = TRUE; + + for (bx = 0; bx < mISL_FG_BLOCK_X_NUM; bx++) { + u8 normal_trees = 0; + u8 other_trees = 0; + + mAGrw_SetTree0Info(tree0_info, island_block->items[0]); + grow_info.block_x = island_block_x_nums[bx]; + grow_info.block_z = mISL_BLOCK_Z; + col = mFI_GetBkNum2ColTop(grow_info.block_x, mISL_BLOCK_Z); + + if (col != NULL) { + if (proc_type == mAGrw_GROW) { + mAGrw_SetAroundBlockInfoIsland(&grow_info, bx); + } + + mAGrw_GrowBlockFgItem(island_block->items[0], col, Save_Get(island.deposit[bx]), &grow_info, proc_type + mAGrw_GROW_ISLAND_FIRST); + } + + mAGrw_ResetTree0Info(tree0_info, &normal_trees, &other_trees, island_block->items[0]); + mAGrw_ThinTree(island_block->items[0], tree0_info, normal_trees, other_trees, mAGrw_ISL_MAX_TREES_PER_BLOCK); + + island_block++; + } + + mAGrw_LimitTreeLineIsland(Save_Get(island).fgblock[0]); +} + +static void mAGrw_CancelOn(u16* cancel, int x, int z) { + if (x < 0) return; + if (x >= FG_BLOCK_X_NUM * UT_X_NUM) return; + if (z < 0) return; + if (z >= FG_BLOCK_Z_NUM * UT_Z_NUM) return; + + { + int bx = x / UT_X_NUM; + int bz = z / UT_Z_NUM; + int ut_x = x % UT_X_NUM; + int ut_z = z % UT_Z_NUM; + + cancel += (bx + bz * FG_BLOCK_X_NUM) * UT_Z_NUM; + cancel[ut_z] |= (1 << ut_x); + } +} + +static int mAGrw_CheckCancel12(mActor_name_t item) { + if ( + (item == GOLD_TREE_S0) || + (item == TREE_S0 || item == TREE_S1) || + (item == TREE_APPLE_S0 || item == TREE_APPLE_S1) || + (item == TREE_ORANGE_S0 || item == TREE_ORANGE_S1) || + (item == TREE_PEACH_S0 || item == TREE_PEACH_S1) || + (item == TREE_PEAR_S0 || item == TREE_PEAR_S1) || + (item == TREE_CHERRY_S0 || item == TREE_CHERRY_S1) || + (item == TREE_1000BELLS_S0 || item == TREE_1000BELLS_S1) || + (item == TREE_10000BELLS_S0 || item == TREE_10000BELLS_S1) || + (item == TREE_30000BELLS_S0 || item == TREE_30000BELLS_S1) || + (item == TREE_100BELLS_S0 || item == TREE_100BELLS_S1) || + (item == TREE_PALM_S0 || item == TREE_PALM_S1) || + (item == CEDAR_TREE_S0 || item == CEDAR_TREE_S1) || + (item == GOLD_TREE_S1) + ) { + return TRUE; + } + + return FALSE; +} + +static int mAGrw_CheckCancel32(mActor_name_t item) { + if ( + (item == TREE_S2 || item == TREE) || + (item == TREE_1000BELLS_S2 || item == TREE_1000BELLS) || + (item == TREE_10000BELLS_S2 || item == TREE_10000BELLS) || + (item == TREE_30000BELLS_S2 || item == TREE_30000BELLS) || + (item == TREE_100BELLS_S2 || item == TREE_100BELLS) || + (item == CEDAR_TREE_S2 || item == CEDAR_TREE) || + (item == GOLD_TREE_S2 || item == GOLD_TREE_SHOVEL || item == GOLD_TREE) || + (item == TREE_APPLE_S2 || item == TREE_APPLE_NOFRUIT_0 || item == TREE_APPLE_NOFRUIT_1 || item == TREE_APPLE_NOFRUIT_2 || item == TREE_APPLE_FRUIT) || + (item == TREE_ORANGE_S2 || item == TREE_ORANGE_NOFRUIT_0 || item == TREE_ORANGE_NOFRUIT_1 || item == TREE_ORANGE_NOFRUIT_2 || item == TREE_ORANGE_FRUIT) || + (item == TREE_PEACH_S2 || item == TREE_PEACH_NOFRUIT_0 || item == TREE_PEACH_NOFRUIT_1 || item == TREE_PEACH_NOFRUIT_2 || item == TREE_PEACH_FRUIT) || + (item == TREE_PEAR_S2 || item == TREE_PEAR_NOFRUIT_0 || item == TREE_PEAR_NOFRUIT_1 || item == TREE_PEAR_NOFRUIT_2 || item == TREE_PEAR_FRUIT) || + (item == TREE_CHERRY_S2 || item == TREE_CHERRY_NOFRUIT_0 || item == TREE_CHERRY_NOFRUIT_1 || item == TREE_CHERRY_NOFRUIT_2 || item == TREE_CHERRY_FRUIT) || + (item == TREE_PALM_S2 || item == TREE_PALM_NOFRUIT_0 || item == TREE_PALM_NOFRUIT_1 || item == TREE_PALM_NOFRUIT_2 || item == TREE_PALM_FRUIT) || + (item == TREE_BEES || item == TREE_FTR || item == TREE_LIGHTS || item == TREE_PRESENT) || + (item == TREE_BELLS) || + (item == CEDAR_TREE_BELLS || item == CEDAR_TREE_FTR || item == CEDAR_TREE_BEES) || + (item == CEDAR_TREE_LIGHTS) || + (item == GOLD_TREE_BELLS || item == GOLD_TREE_FTR || item == GOLD_TREE_BEES) + ) { + return TRUE; + } + + return FALSE; +} + +static int mAGrw_CheckCancel22(mActor_name_t item) { + switch (item) { + case MAP_BOARD0: + case MESSAGE_BOARD0: + case MUSIC_BOARD0: + return TRUE; + + default: + return FALSE; + } +} + +static int mAGrw_CheckCancel36(mActor_name_t item) { + if (ITEM_NAME_GET_TYPE(item) == NAME_TYPE_STRUCT) { + if ( + (item >= SIGN00 && item <= SIGN20) || + (item >= NPC_HOUSE_START && item <= NPC_HOUSE_END) || + (item == KAMAKURA) || + (item == POLICE_STATION) || + (item == TENT) + ) { + return TRUE; + } + } + + return FALSE; +} + +static int mAGrw_CheckHide36(mActor_name_t item) { + if (ITEM_NAME_GET_TYPE(item) == NAME_TYPE_STRUCT) { + if ( + (item >= NPC_HOUSE_START && item <= NPC_HOUSE_END) || + (item == KAMAKURA) || + (item == POLICE_STATION) || + (item == TENT) + ) { + return TRUE; + } + } + + return FALSE; +} + +static int mAGrw_CheckCancelLeft45(mActor_name_t item) { + if (ITEM_NAME_GET_TYPE(item) == NAME_TYPE_STRUCT) { + if ( + (item == HOUSE0) || + (item == HOUSE2) + ) { + return TRUE; + } + } + + return FALSE; +} + +static int mAGrw_CheckCancelRight45(mActor_name_t item) { + if (ITEM_NAME_GET_TYPE(item) == NAME_TYPE_STRUCT) { + if ( + (item == HOUSE1) || + (item == HOUSE3) + ) { + return TRUE; + } + } + + return FALSE; +} + +static int mAGrw_CheckCancel46(mActor_name_t item) { + switch (item) { + case POST_OFFICE: + case SHOP0: + case NEEDLEWORK_SHOP: + return TRUE; + + default: + return FALSE; + } +} + +static int mAGrw_CheckCancel23(mActor_name_t item) { + if (item == TOUDAI) { + return TRUE; + } + + return FALSE; +} + +static int mAGrw_CheckCancel57(mActor_name_t item) { + if (item == SHOP1) { + return TRUE; + } + + return FALSE; +} + +static int mAGrw_CheckCancel68(mActor_name_t item) { + if (item == SHOP2 || item == SHOP3) { + return TRUE; + } + + return FALSE; +} + +static int mAGrw_CheckCancel77(mActor_name_t item) { + if (item == MUSEUM) { + return TRUE; + } + + return FALSE; +} + +static void mAGrw_SetCancelOn(u16* cancel, int x_base, int z_base, int x_start, int x_end, int z_start, int z_end) { + int z; + int x; + + for (z = z_start; z <= z_end; z++) { + for (x = x_start; x <= x_end; x++) { + mAGrw_CancelOn(cancel, x_base + x, z_base + z); + } + } +} + +typedef int (*mAGrw_CHECK_CANCEL_UT_PROC)(mActor_name_t); + +static void mAGrw_SetblockCancelUtInfo(u16* cancel_ut, mActor_name_t* items, int x_base, int z_base) { + static mAGrw_CHECK_CANCEL_UT_PROC check_cancel[mAGrw_CHECK_CANCEL_NUM] = { + &mAGrw_CheckCancel12, + &mAGrw_CheckCancel32, + &mAGrw_CheckCancel22, + &mAGrw_CheckCancel36, + &mAGrw_CheckCancelLeft45, + &mAGrw_CheckCancelRight45, + &mAGrw_CheckCancel46, + &mAGrw_CheckCancel23, + &mAGrw_CheckCancel57, + &mAGrw_CheckCancel68, + &mAGrw_CheckCancel77 + }; + + int ut_z; + int ut_x; + int proc; + + for (ut_z = 0; ut_z < UT_Z_NUM; ut_z++) { + for (ut_x = 0; ut_x < UT_X_NUM; ut_x++) { + for (proc = 0; proc < mAGrw_CHECK_CANCEL_NUM; proc++) { + if ((*check_cancel[proc])(*items) == TRUE) { + mAGrw_SetCancelOn(cancel_ut, x_base + ut_x, z_base + ut_z, l_non_area[proc][0], l_non_area[proc][1], l_non_area[proc][2], l_non_area[proc][3]); + mAGrw_SetCancelOn(cancel_ut, x_base + ut_x, z_base + ut_z, 0, 0, 0, 0); + + break; + } + } + + items++; + } + } +} + +static void mAGrw_HideOn(u16* hide, int ut_x, int ut_z) { + if (ut_x < 0) return; + if (ut_x >= UT_X_NUM) return; + if (ut_z < 0) return; + if (ut_z >= UT_Z_NUM) return; + + hide[ut_z] |= (1 << ut_x); +} + +static void mAGrw_SetHideOn(u16* hide, int x_base, int z_base, mAGrw_HideAreaTable_c* hide_area) { + mAGrw_HideArea_c* hide_p = hide_area->hide_p; + int num = hide_area->num; + int i; + + if (num > 0 && hide_p != NULL) { + for (i = 0; i < num; i++) { + mAGrw_HideOn(hide, x_base + hide_p->x_ofs, z_base + hide_p->z_ofs); + hide_p++; + } + } +} + +extern void mAGrw_SetHideUtInfo(u16* hide, mActor_name_t* items) { + static mAGrw_CHECK_CANCEL_UT_PROC check_hide[mAGrw_CHECK_CANCEL_NUM] = { + &mAGrw_CheckCancel12, + &mAGrw_CheckCancel32, + &mAGrw_CheckCancel22, + &mAGrw_CheckHide36, + &mAGrw_CheckCancelLeft45, + &mAGrw_CheckCancelRight45, + &mAGrw_CheckCancel46, + &mAGrw_CheckCancel23, + &mAGrw_CheckCancel57, + &mAGrw_CheckCancel68, + &mAGrw_CheckCancel77 + }; + + int i; + int ut_z; + int ut_x; + + if (hide != NULL && items != NULL) { + for (ut_z = 0; ut_z < UT_Z_NUM; ut_z++) { + for (ut_x = 0; ut_x < UT_X_NUM; ut_x++) { + for (i = 0; i < mAGrw_CHECK_CANCEL_NUM; i++) { + if ((*check_hide[i])(*items) == TRUE) { + mAGrw_SetHideOn(hide, ut_x, ut_z, &l_hide_area_table[i]); + + break; + } + } + + items++; + } + } + } +} + +static void mAGrw_SetCancelUtInfo(u16* cancel) { + mFM_fg_c* fg_block = Save_Get(fg[0]); + int z_base; + int bz; + int bx; + + bzero(cancel, FG_BLOCK_TOTAL_NUM * UT_Z_NUM * sizeof(u16)); + z_base = 0; + + for (bz = 0; bz < FG_BLOCK_Z_NUM; bz++) { + for (bx = 0; bx < FG_BLOCK_X_NUM; bx++) { + mAGrw_SetblockCancelUtInfo(cancel, fg_block->items[0], bx * UT_X_NUM, bz * UT_Z_NUM); + fg_block++; + } + } +} + +static void mAGrw_GetDepositAbleFlatNum(u8* candidate_num, u8* flat_num, mActor_name_t* items, mCoBG_Collision_u* col, u16* cancel) { + int ut_z; + int ut_x; + + *candidate_num = 0; + *flat_num = 0; + + if (items != NULL && col != NULL) { + for (ut_z = 0; ut_z < UT_Z_NUM; ut_z++) { + for (ut_x = 0; ut_x < UT_X_NUM; ut_x++) { + /* Check that the cancel flag for the unit isn't set, that the unit has no item, and that a hole can be dug */ + if ( + (((cancel[0] >> ut_x) & 1) != 1) && + (items[0] == EMPTY_NO) && + (mCoBG_CheckHole_OrgAttr(col->data.unit_attribute)) + ) { + candidate_num[0]++; + + /* Check if the unit collision data is a flat square */ + if ( + (col->data.center == col->data.top_left) && + (col->data.center == col->data.bot_left) && + (col->data.center == col->data.top_right) && + (col->data.center == col->data.bot_right) && + (mCoBG_CheckSandHole_ClData(col) != TRUE) + ) { + flat_num[0]++; + } + } + + items++; + col++; + } + + cancel++; + } + } +} + +static void mAGrw_SetShineGroundBlock(mAGrw_SSPosInfo_c* pos_info, mActor_name_t* items, mCoBG_Collision_u* col, u8 flat_num, u16* cancel) { + int selected_ut = RANDOM(flat_num); + + int ut_z; + int ut_x; + + for (ut_z = 0; ut_z < UT_Z_NUM; ut_z++) { + for (ut_x = 0; ut_x < UT_X_NUM; ut_x++) { + /* Check that the cancel flag for the unit isn't set, that the unit has no item, and that a hole can be dug */ + if ( + (((cancel[0] >> ut_x) & 1) != 1) && + (items[0] == EMPTY_NO) && + (mCoBG_CheckHole_OrgAttr(col->data.unit_attribute)) + ) { + /* Check if the unit collision data is a flat square */ + if ( + (col->data.center == col->data.top_left) && + (col->data.center == col->data.bot_left) && + (col->data.center == col->data.top_right) && + (col->data.center == col->data.bot_right) && + (mCoBG_CheckSandHole_ClData(col) != TRUE) + ) { + if (selected_ut == 0) { + pos_info->ut_x = ut_x; + pos_info->ut_z = ut_z; + cancel[0] |= (1 << ut_x); // update unit as taken + + ut_z = UT_Z_NUM; + break; + } + else { + selected_ut--; + } + } + } + + items++; + col++; + } + + cancel++; + } +} + +static void mAGrw_SetShineGround_com(mAGrw_SSPosInfo_c* pos_info, u8* block_flat_candidates, u8* flat_num, u8* block_candidates, u8* candidate_num, u16* cancel) { + int selected_block; + mFM_fg_c* fg_block; + + int i; + + if (block_flat_candidates[0] != 0) { + selected_block = RANDOM(block_flat_candidates[0]); + fg_block = Save_Get(fg[0]); + + for (i = 0; i < FG_BLOCK_TOTAL_NUM; i++) { + if (flat_num[0] != 0) { + if (selected_block == 0) { + int bx = (i % FG_BLOCK_X_NUM) + 1; + int bz = (i / FG_BLOCK_X_NUM) + 1; + + pos_info->block_x = bx; + pos_info->block_z = bz; + + mAGrw_SetShineGroundBlock(pos_info, fg_block->items[0], mFI_GetBkNum2ColTop(bx, bz), flat_num[0], cancel); + flat_num[0]--; + if (flat_num[0] == 0) { + block_flat_candidates[0]--; + } + + candidate_num[0]--; + if (candidate_num[0] == 0) { + block_candidates[0]--; // remove this block from possible candidates + } + + break; + } + else { + selected_block--; + } + } + + flat_num++; + candidate_num++; + fg_block++; + cancel += UT_Z_NUM; + } + } +} + +static void mAGrw_SetShineGround(mAGrw_SSPosInfo_c* pos_info, u8* block_flat_candidates, u8* flat_num, u8* block_candidates, u8* candidate_num, u16* cancel) { + mAGrw_SSPosInfo_c* p_info = pos_info; + int i; + + for (i = 0; i < TOTAL_PLAYER_NUM; i++) { + mAGrw_ClearSSPosInfo_com(p_info); + mAGrw_SetShineGround_com(p_info, block_flat_candidates, flat_num, block_candidates, candidate_num, cancel); + + p_info++; + } +} + +static void mAGrw_SetHaniwaBlock(mActor_name_t* items, mActor_name_t haniwa_item, mCoBG_Collision_u* col, u16* deposit, u16* cancel, u8 depositable_num) { + mMsm_DepositItemBlock_cancel(items, haniwa_item, col, deposit, cancel, depositable_num); +} + +static void mAGrw_SetHaniwa(u8* block_candidates, u8* candidate_num, u16* cancel) { + mActor_name_t haniwas[mAGrw_HANIWA_NUM]; + u8 depositable_num; + int selected_block; + u8* candidate_num_p = candidate_num; + u16* cancel_p = cancel; + int bz; + int bx; + int i; + int block; + + mSP_RandomHaniwaSelect(haniwas, mAGrw_HANIWA_NUM); + + for (i = 0; i < mAGrw_HANIWA_NUM; i++) { + candidate_num = candidate_num_p; + cancel = cancel_p; + + if (block_candidates[0] == 0) { + break; // no candidate blocks for placing a haniwa down + } + + selected_block = RANDOM(block_candidates[0]); + + for (block = 0; block < FG_BLOCK_TOTAL_NUM; block++) { + depositable_num = candidate_num[0]; + + if (depositable_num != 0) { + if (selected_block <= 0) { + bx = block % FG_BLOCK_X_NUM; + bz = block / FG_BLOCK_X_NUM; + + mAGrw_SetHaniwaBlock( + Save_Get(fg[bz][bx]).items[0], + haniwas[i], + mFI_GetBkNum2ColTop(bx + 1, bz + 1), + Save_Get(deposit[block]), + cancel, + depositable_num + ); + + if (block_candidates[0] > 1) { + block_candidates[0]--; + candidate_num[0] = 0; + } + + break; + } + else { + selected_block--; + } + } + + candidate_num++; + cancel += UT_Z_NUM; + } + } +} + +static u8 l_candidate_flat_num[FG_BLOCK_TOTAL_NUM]; /* TODO: this is definitely going to be bss ordering issue */ + +static void mAGrw_SetDigItem(mAGrw_SSPosInfo_c* pos_info, int* deposit_haniwa, u16* cancel) { + mFM_fg_c* fg = Save_Get(fg[0]); + u8 block_candidates = 0; + u8 block_flat_candidates = 0; + u8* candidate_num_p = l_candidate_num; + u8* candidate_flat_num_p = l_candidate_flat_num; + u16* cancel_p = cancel; + int bz; + int bx; + + bzero(l_candidate_num, FG_BLOCK_TOTAL_NUM * sizeof(u8)); + bzero(l_candidate_flat_num, FG_BLOCK_TOTAL_NUM * sizeof(u8)); + for (bz = 0; bz < FG_BLOCK_Z_NUM; bz++) { + for (bx = 0; bx < FG_BLOCK_X_NUM; bx++) { + if ( + mFI_CheckBlockKind_OR( + bx + 1, + bz + 1, + mRF_BLOCKKIND_PLAYER | mRF_BLOCKKIND_SHRINE | mRF_BLOCKKIND_STATION | mRF_BLOCKKIND_POOL | mRF_BLOCKKIND_DUMP + ) == FALSE + ) { + mAGrw_GetDepositAbleFlatNum(candidate_num_p, candidate_flat_num_p, fg->items[0], mFI_GetBkNum2ColTop(bx + 1, bz + 1), cancel); + + if (candidate_num_p[0] != 0) { + block_candidates++; + } + + if (candidate_flat_num_p[0] != 0) { + block_flat_candidates++; + } + } + + candidate_num_p++; + candidate_flat_num_p++; + fg++; + cancel += UT_Z_NUM; + } + } + + mAGrw_SetShineGround(pos_info, &block_flat_candidates, l_candidate_flat_num, &block_candidates, l_candidate_num, cancel_p); + + if (deposit_haniwa[0] == TRUE) { + mAGrw_SetHaniwa(&block_candidates, l_candidate_num, cancel_p); + deposit_haniwa[0] = FALSE; + } +} + +static void mAGrw_SpoilPossession(mActor_name_t* items, int count) { + for (count; count != 0; count--) { + mAGrw_SpoilKabu(items, NULL); + items++; + } +} + +static void mAGrw_SpoilAllPossession(int spoil_kabu) { + Private_c* priv; + Haniwa_Item_c* haniwa_item; + + int i; + int j; + int k; + + if (spoil_kabu == TRUE) { + priv = Save_Get(private); + + for (i = 0; i < PLAYER_NUM; i++) { + mAGrw_SpoilPossession(priv->inventory.pockets, mPr_POCKETS_SLOT_COUNT); + priv++; + } + + if (Common_Get(player_no) == mPr_FOREIGNER) { + mAGrw_SpoilPossession(Common_Get(now_private)->inventory.pockets, mPr_POCKETS_SLOT_COUNT); + } + + for (i = 0; i < mHS_HOUSE_NUM; i++) { + for (j = 0; j < mHm_ROOM_NUM; j++) { + for (k = 0; k < mHm_LAYER_NUM; k++) { + mAGrw_SpoilPossession((&Save_Get(homes[i]).floors[j].layer_main)[k].items[0], UT_TOTAL_NUM); + } + } + + haniwa_item = Save_Get(homes[i]).haniwa.items; + for (j = 0; j < HANIWA_ITEM_HOLD_NUM; j++) { + mAGrw_SpoilKabu(&haniwa_item->item, NULL); + haniwa_item++; + } + } + } +} + +static int mAGrw_CheckClearDumpDay(lbRTC_time_c* grow_time, lbRTC_time_c* now_time) { + static int clean_week[2] = { lbRTC_MONDAY, lbRTC_THURSDAY }; + + int delta_days; + lbRTC_time_c temp; + int add_days; + int weekday; + int res = FALSE; + int i; + + if (lbRTC_IsOverTime(grow_time, now_time) == lbRTC_OVER) { + delta_days = lbRTC_GetIntervalDays(grow_time, now_time); + } + else { + delta_days = lbRTC_GetIntervalDays(now_time, grow_time); + } + + if (delta_days >= lbRTC_WEEK) { + res = TRUE; + } + else { + for (i = 0; i < 2; i++) { + add_days = 0; + lbRTC_TimeCopy(&temp, grow_time); + + if (temp.weekday > clean_week[i]) { + add_days = (lbRTC_WEEK - temp.weekday) + clean_week[i]; + } + else if (temp.weekday < clean_week[i]) { + add_days = clean_week[i] - temp.weekday; + } + + lbRTC_Add_DD(&temp, add_days); + + if (lbRTC_IsOverTime(&temp, now_time) == lbRTC_OVER) { + res = TRUE; + + break; + } + } + } + + return res; +} + +extern void mAGrw_SearchDump(mFI_unit_c* dump_info) { + if (mFI_BlockKind2BkNum(&dump_info->block_x, &dump_info->block_z, mRF_BLOCKKIND_DUMP)) { + mActor_name_t* fg = mFI_BkNumtoUtFGTop(dump_info->block_x, dump_info->block_z); + dump_info->block_data = fg; + + if (fg != NULL) { + int i; + + for (i = 0; i < UT_TOTAL_NUM; i++) { + if (fg[0] == DUMP) { + dump_info->unit_x = i & 15; + dump_info->unit_z = i >> 4; + + break; + } + + fg++; + } + } + } + else { + dump_info->block_x = -1; + dump_info->block_z = -1; + dump_info->block_data = NULL; + } +} + +static void mAGrw_ClearDumpArea(mFI_unit_c* dump_info) { + mActor_name_t* dump_item; + u16* deposit; + int ut_x; + int ut_z; + int row; + int col; + + deposit = mFI_GetDepositP(dump_info->block_x, dump_info->block_z); + + ut_x = dump_info->unit_x - 4; + ut_z = dump_info->unit_z - 4; + dump_item = dump_info->block_data + dump_info->unit_x + (dump_info->unit_z * UT_X_NUM); + + dump_item -= (4 * UT_X_NUM) + 4; /* dump is 4x4 so move back to the actual start */ + + for (row = 0; row < 4; row++) { + for (col = 0; col < 4; col++) { + if (dump_item != NULL) { + mSN_ClearSnowman(dump_item); + *dump_item = EMPTY_NO; + + if (deposit != NULL) { + mFI_BlockDepositOFF(deposit, ut_x + col, ut_z + row); + } + } + + dump_item++; + } + + dump_item += 12; /* move on to the next row */ + } +} + +static void mAGrw_ClearDump(mFI_unit_c* dump_info, lbRTC_time_c* grow_time, lbRTC_time_c* now_time) { + if (mAGrw_CheckClearDumpDay(grow_time, now_time) == TRUE && dump_info->block_data != NULL) { + mAGrw_ClearDumpArea(dump_info); + } +} + +static mActor_name_t mAGrw_GetSetItemDump() { + static int category[10] = { + mSP_KIND_FURNITURE, + mSP_KIND_FURNITURE, + mSP_KIND_CLOTH, + mSP_KIND_CLOTH, + mSP_KIND_CLOTH, + mSP_KIND_CLOTH, + mSP_KIND_PAPER, + mSP_KIND_PAPER, + mSP_KIND_PAPER, + mSP_KIND_MAX + }; + + mActor_name_t set_item = EMPTY_NO; + int cat = category[RANDOM(10)]; + + if (cat == mSP_KIND_MAX) { + mSP_RandomUmbSelect(&set_item, 1); + } + else { + mSP_SelectRandomItem_New(NULL, &set_item, 1, NULL, 0, cat, mSP_LISTTYPE_ABC, FALSE); + } + + return set_item; +} + +static void mAGrw_SetItemDumpBlock(mActor_name_t* items) { + int col; + int row; + mActor_name_t* dump_item = items; + int empty_slots = 0; + + for (row = 0; row < 4; row++) { + for (col = 0; col < 4; col++) { + if (*items == EMPTY_NO) { + empty_slots++; + } + + items++; + } + + items += 12; /* move on to the next row */ + } + + if (empty_slots > 0) { + int selected_ut = RANDOM(empty_slots); + items = dump_item; + + for (row = 0; row < 4; row++) { + for (col = 0; col < 4; col++) { + if (*items == EMPTY_NO) { + if (selected_ut <= 0) { + *items = mAGrw_GetSetItemDump(); + + row = 4; + break; + } + else { + selected_ut--; + } + } + + items++; + } + + items += 12; /* move on to the next row */ + } + } +} + +static void mAGrw_SetItemDump(mFI_unit_c* dump_info) { + int used_spots = 0; + int i; + + if (dump_info->block_data != NULL) { + mActor_name_t* dump_item_p; + mActor_name_t* dump_item = dump_info->block_data + dump_info->unit_x + (dump_info->unit_z * UT_X_NUM); + int row; + int col; + + dump_item -= (4 * UT_X_NUM) + 4; /* dump is 4x4 so move back to the actual start */ + dump_item_p = dump_item; + for (row = 0; row < 4; row++) { + for (col = 0; col < 4; col++) { + if (*dump_item != EMPTY_NO) { + used_spots++; + } + + dump_item++; + } + + dump_item += 12; /* move on to the next row */ + } + + if (used_spots <= 7) { + for (i = 0; i < mAGrw_DUMP_ITEM_NUM; i++) { + mAGrw_SetItemDumpBlock(dump_item_p); + } + } + } +} + +static int mAGrw_GetGrassMax(lbRTC_time_c* now_time, lbRTC_time_c* grow_time) { + int delta_days; + int grass_days; + + if (lbRTC_IsOverTime(grow_time, now_time) == lbRTC_OVER) { + delta_days = lbRTC_GetIntervalDays(grow_time, now_time); + } + else { + delta_days = lbRTC_GetIntervalDays(now_time, grow_time); + } + + delta_days++; + if (delta_days > 1 && now_time->hour < 6) { + delta_days--; + } + + return delta_days * mAGrw_GRASS_PER_DAY; +} + +static u8 mAGrw_GetChangeAbleGrass(mActor_name_t* items, mCoBG_Collision_u* col, u16* cancel, int bx, int bz) { + xyz_t wpos_temp = { 0.0f, 0.0f, 0.0f }; + xyz_t wpos = { 0.0f, 0.0f, 0.0f }; + u8 change_able_grass = 0; + int ut_z; + int ut_x; + + mFI_BkNum2WposXZ(&wpos.x, &wpos.z, bx, bz); + + wpos.x += mFI_UT_WORLDSIZE_X_F / 2.0f; + wpos.z += mFI_UT_WORLDSIZE_Z_F / 2.0f; + + wpos_temp = wpos; + for (ut_z = 0; ut_z < UT_Z_NUM; ut_z++) { + wpos_temp.x = wpos.x; + for (ut_x = 0; ut_x < UT_X_NUM; ut_x++) { + if ( + ((cancel[0] >> ut_x) & 1) != 1 && + (items[0] == EMPTY_NO) && + (mCoBG_Attribute2CheckPlant(col->data.unit_attribute, &wpos_temp) == mCoBG_PLANT4) + ) { + change_able_grass++; + } + + items++; + col++; + wpos_temp.x += mFI_UT_WORLDSIZE_X_F; + } + + cancel++; + wpos_temp.z += mFI_UT_WORLDSIZE_Z_F; + } + + return change_able_grass; +} + +static void mAGrw_PutGrassBlock(mActor_name_t* items, mActor_name_t grass, mCoBG_Collision_u* col, u8* change_able_grass, u16* cancel, int bx, int bz) { + xyz_t wpos_temp = { 0.0f, 0.0f, 0.0f }; + xyz_t wpos = { 0.0f, 0.0f, 0.0f }; + int selected_ut; + int ut_z; + int ut_x; + + mFI_BkNum2WposXZ(&wpos.x, &wpos.z, bx, bz); + + wpos.x += mFI_UT_WORLDSIZE_X_F / 2.0f; + wpos.z += mFI_UT_WORLDSIZE_Z_F / 2.0f; + + wpos_temp = wpos; + selected_ut = RANDOM(*change_able_grass); + for (ut_z = 0; ut_z < UT_Z_NUM; ut_z++) { + wpos_temp.x = wpos.x; + for (ut_x = 0; ut_x < UT_X_NUM; ut_x++) { + if ( + ((cancel[0] >> ut_x) & 1) != 1 && + (items[0] == EMPTY_NO) && + (mCoBG_Attribute2CheckPlant(col->data.unit_attribute, &wpos_temp) == mCoBG_PLANT4) + ) { + if (selected_ut <= 0) { + items[0] = grass; + change_able_grass[0]--; + + return; + } + else { + selected_ut--; + } + } + + items++; + col++; + wpos_temp.x += mFI_UT_WORLDSIZE_X_F; + } + + cancel++; + wpos_temp.z += mFI_UT_WORLDSIZE_Z_F; + } +} + +#ifndef MUST_MATCH +/* @nonmatching */ +static void mAGrw_SetGrass(lbRTC_time_c* now_time, lbRTC_time_c* grow_time, u16* cancel) { + mActor_name_t grass_table[mAGrw_GRASS_TABLE_NUM]; + u16* cancel_p = cancel; + mFM_fg_c* fg_block = Save_Get(fg[0]); + u8* candidate_num = l_candidate_num; + mCoBG_Collision_u* col; + int grass_table_idx = 0; + int candidate_blocks = 0; + int grass_max; + mFM_fg_c* fg_block_p = fg_block; + int selected_block; + int bx; + int bz; + int i; + int j; + + mAGrw_MakeGrassTable(grass_table); + bzero(l_candidate_num, FG_BLOCK_TOTAL_NUM * sizeof(u8)); + grass_max = mAGrw_GetGrassMax(now_time, grow_time); + + for (bz = 1; bz < FG_BLOCK_Z_NUM + 1; bz++) { + for (bx = 1; bx < FG_BLOCK_X_NUM + 1; bx++) { + col = mFI_GetBkNum2ColTop(bx, bz); + + if (fg_block_p != NULL && col != NULL) { + candidate_num[0] = mAGrw_GetChangeAbleGrass(fg_block_p->items[0], col, cancel_p, bx, bz); + + if (candidate_num[0] != 0) { + candidate_blocks++; + } + } + + candidate_num++; + fg_block_p++; + cancel_p += UT_Z_NUM; + } + } + + for (i = 0; i < grass_max; i++) { + if (candidate_blocks <= 0) { + break; + } + + fg_block_p = fg_block; + cancel_p = cancel; + selected_block = RANDOM(candidate_blocks); + candidate_num = l_candidate_num; + + for (j = 0; j < FG_BLOCK_TOTAL_NUM; j++) { + if (candidate_num[0] != 0) { + if (selected_block <= 0) { + bz = (j / FG_BLOCK_X_NUM) + 1; + bx = (j % FG_BLOCK_X_NUM) + 1; + + mAGrw_PutGrassBlock(fg_block_p->items[0], grass_table[grass_table_idx], mFI_GetBkNum2ColTop(bx, bz), candidate_num, cancel_p, bx, bz); + + if (candidate_num[0] == 0) { + candidate_blocks--; + } + + break; + } + else { + selected_block--; + } + } + + candidate_num++; + fg_block_p++; + cancel_p += UT_Z_NUM; + } + + grass_table_idx++; + if (grass_table_idx >= mAGrw_GRASS_TABLE_NUM) { + grass_table_idx = 0; + } + } +} +#else +extern f64 lbl_806490a8; +REL_SYMBOL_AT(lbl_806490a8, 0x806490A8); + +static asm void mAGrw_SetGrass(lbRTC_time_c* now_time, lbRTC_time_c* grow_time, u16* cancel) { + #include "asm/8051497c.s" +} +#endif + +static void mAGrw_ClearGrass() { + mFM_fg_c* fg_block = Save_Get(fg[0]); + mActor_name_t* items; + int block; + int unit; + + for (block = 0; block < FG_BLOCK_TOTAL_NUM; block++) { + items = fg_block->items[0]; + for (unit = 0; unit < UT_TOTAL_NUM; unit++) { + if (IS_ITEM_GRASS(items[0])) { + items[0] = EMPTY_NO; + } + + items++; + } + + fg_block++; + } +} + +static void mAGrw_AllMeltSnowman() { + mFM_fg_c* fg_block = Save_Get(fg[0]); + mActor_name_t* items; + int block; + int unit; + + + for (block = 0; block < FG_BLOCK_TOTAL_NUM; block++) { + items = fg_block->items[0]; + for (unit = 0; unit < UT_TOTAL_NUM; unit++) { + mSN_ClearSnowman(items); + + items++; + } + + fg_block++; + } +} + +static void mAgrw_ZuruSpoilKabuBlockFgItem(mActor_name_t* items, mCoBG_Collision_u* col, mAGrw_GrowInfo_c* grow_info) { + xyz_t wpos_temp; + xyz_t wpos = { 0.0f, 0.0f, 0.0f }; + int ut_z; + int ut_x; + + mFI_BkNum2WposXZ(&wpos.x, &wpos.z, grow_info->block_x, grow_info->block_z); + wpos.x += mFI_UT_WORLDSIZE_X_F / 2.0f; + wpos.z += mFI_UT_WORLDSIZE_Z_F / 2.0f; + + wpos_temp = wpos; + for (ut_z = 0; ut_z < UT_Z_NUM; ut_z++) { + wpos_temp.x = wpos.x; + for (ut_x = 0; ut_x < UT_X_NUM; ut_x++) { + grow_info->ut_x = ut_x; + grow_info->ut_z = ut_z; + + mAGrw_SpoilKabu(items, grow_info); + items++; + wpos_temp.x += mFI_UT_WORLDSIZE_X_F; + } + wpos_temp.z += mFI_UT_WORLDSIZE_X_F; + } +} + +static void mAGrw_ZuruSpoilKabuFieldFgItem() { + mAGrw_GrowInfo_c grow_info; + mFM_fg_c* fg_block = Save_Get(fg[0]); + mCoBG_Collision_u* col; + int bz; + int bx; + + mAGrw_ClearGrowInfo(&grow_info); + grow_info.spoil_kabu = TRUE; + + for (bz = 0; bz < FG_BLOCK_Z_NUM; bz++) { + for (bx = 0; bx < FG_BLOCK_X_NUM; bx++) { + grow_info.block_x = bx + 1; + grow_info.block_z = bz + 1; + + col = mFI_GetBkNum2ColTop(bx + 1, bz + 1); + + if (col != NULL) { + mAgrw_ZuruSpoilKabuBlockFgItem(fg_block->items[0], col, &grow_info); + } + + fg_block++; + } + } +} + +static void mAGrw_ZuruSpoilKabuIslandFgItem(Island_c* island) { + mAGrw_GrowInfo_c grow_info; + mFM_fg_c* fg_block = island->fgblock[0]; + mCoBG_Collision_u* col; + int island_bx[mISL_FG_BLOCK_X_NUM]; + int bx; + + mAGrw_ClearGrowInfo(&grow_info); + grow_info.spoil_kabu = TRUE; + mFI_GetIslandBlockNumX(island_bx); + + for (bx = 0; bx < mISL_FG_BLOCK_X_NUM; bx++) { + grow_info.block_x = island_bx[bx]; + grow_info.block_z = mISL_BLOCK_Z; + + col = mFI_GetBkNum2ColTop(island_bx[bx], mISL_BLOCK_Z); + + if (col != NULL) { + mAgrw_ZuruSpoilKabuBlockFgItem(fg_block->items[0], col, &grow_info); + } + + fg_block++; + } +} + +static void mAGrw_ZuruSpoilKabu(lbRTC_time_c* now_time) { + if ( + Save_Get(save_exist) == TRUE && + lbRTC_IsEqualDate( + now_time->year, now_time->month, now_time->day, + Save_Get(save_check).time.year, Save_Get(save_check).time.month, Save_Get(save_check).time.day + ) < lbRTC_EQUAL + ) { + mAGrw_ZuruSpoilKabuFieldFgItem(); + mAGrw_ZuruSpoilKabuIslandFgItem(Save_GetPointer(island)); + mAGrw_SpoilAllPossession(TRUE); + } +} + +static void mAGrw_SpoilKabuIslandCottage(Island_c* island) { + int i; + + for (i = 0; i < mHm_LAYER_NUM; i++) { + mAGrw_SpoilPossession((&island->cottage.room.layer_main)[i].items[0], UT_TOTAL_NUM); + } +} + +extern void mAGrw_SpoilKabuIsland(Island_c* island) { + mAGrw_ZuruSpoilKabuIslandFgItem(island); + mAGrw_SpoilKabuIslandCottage(island); +} + +static u16 l_cancel_ut[FG_BLOCK_TOTAL_NUM * UT_Z_NUM]; + +extern void mAGrw_RenewalFgItem_ovl(lbRTC_time_c* now_time, int* deposit_haniwa) { + lbRTC_time_c* last_grow_time; + int flower_time; + int is_grow_time_equal; + int is_over_time; + int spoil_kabu; + int proc_type; + u8 fossil_record; + int fossil_num; + lbRTC_time_c grow_time; + mFI_unit_c dump_info; + + last_grow_time = Save_GetPointer(all_grow_renew_time); + fossil_record = 0; + fossil_num = 0; + + if (Save_Get(scene_no) == SCENE_FG) { + flower_time = mAGrw_CheckFlowerTime(now_time); + + if (Save_Get(clear_grass)) { + mAGrw_ClearGrass(); + } + + if (flower_time == FALSE) { + mAGrw_AllMeltSnowman(); + } + + if (Common_Get(event_notification_active) != TRUE) { + is_grow_time_equal = mTM_AreTimesEqual(&mTM_rtcTime_clear_code, last_grow_time); + is_over_time = lbRTC_IsOverTime(last_grow_time, now_time); + + if (is_grow_time_equal == TRUE || is_over_time == lbRTC_LESS) { + if (is_grow_time_equal == TRUE) { + proc_type = mAGrw_GROW_FIRST; + *deposit_haniwa = TRUE; + } + else { + proc_type = mAGrw_GROW_FIRST_FORCE; + } + + lbRTC_TimeCopy(&grow_time, &mTM_rtcTime_clear_code); + mAGrw_SearchDump(&dump_info); + mAGrw_GrowFieldFgItem(now_time, &grow_time, flower_time, FALSE, &fossil_record, &fossil_num, proc_type); + mAGr_GrowIslandFgItem(now_time, &grow_time, flower_time, FALSE, proc_type); + mAGrw_SetCancelUtInfo(l_cancel_ut); + mMsm_DepositFossil(fossil_record, fossil_num, l_cancel_ut, proc_type); + mAGrw_SetDigItem(Save_Get(allgrow_ss_pos_info).shine_pos, deposit_haniwa, l_cancel_ut); + mAGrw_SetShineGround_player(Save_GetPointer(allgrow_ss_pos_info), Common_Get(player_no)); + mAGrw_SetMoneyStone(Save_GetPointer(allgrow_ss_pos_info), Save_Get(fg[0][0]).items[0]); + mAGrw_SetMoneyStone_player(Save_GetPointer(allgrow_ss_pos_info), Common_Get(player_no)); + mAGrw_SetCarp(last_grow_time); + mAGrw_ZuruSpoilKabu(now_time); + lbRTC_TimeCopy(last_grow_time, now_time); + mFAs_SetFieldRank(); + } + else { + lbRTC_TimeCopy(&grow_time, last_grow_time); + grow_time.min = 0; + grow_time.sec = 0; + + if (grow_time.hour >= 6) { + lbRTC_Add_DD(&grow_time, 1); + grow_time.weekday++; + + if (grow_time.weekday >= lbRTC_WEEK) { + grow_time.weekday = lbRTC_SUNDAY; + } + } + + grow_time.hour = 6; + + if (lbRTC_IsOverTime(&grow_time, now_time) == lbRTC_OVER) { + spoil_kabu = mAGrw_CheckSpoilKabuTime(&grow_time, now_time); + mAGrw_SearchDump(&dump_info); + mAGrw_GrowFieldFgItem(now_time, &grow_time, flower_time, spoil_kabu, &fossil_record, &fossil_num, mAGrw_GROW); + mAGr_GrowIslandFgItem(now_time, &grow_time, flower_time, spoil_kabu, mAGrw_GROW); + mAGrw_SetCancelUtInfo(l_cancel_ut); + mMsm_DepositFossil(fossil_record, fossil_num, l_cancel_ut, mAGrw_GROW); + mAGrw_SetDigItem(Save_Get(allgrow_ss_pos_info).shine_pos, deposit_haniwa, l_cancel_ut); + mAGrw_SetShineGround_player(Save_GetPointer(allgrow_ss_pos_info), Common_Get(player_no)); + mAGrw_SetMoneyStone(Save_GetPointer(allgrow_ss_pos_info), Save_Get(fg[0][0]).items[0]); + mAGrw_SetMoneyStone_player(Save_GetPointer(allgrow_ss_pos_info), Common_Get(player_no)); + mAGrw_SpoilAllPossession(spoil_kabu); + mAGrw_ClearDump(&dump_info, &grow_time, now_time); + + if (Save_Get(clear_grass) == FALSE) { + mAGrw_SetGrass(now_time, &grow_time, l_cancel_ut); + } + + mAGrw_SetCarp(last_grow_time); + mPB_force_set_keep_item(); + mAGrw_SetItemDump(&dump_info); + lbRTC_TimeCopy(last_grow_time, now_time); + mFAs_SetFieldRank(); + } + } + + Save_Set(clear_grass, FALSE); + } + } +}