diff --git a/include/libforest/gbi_extensions.h b/include/libforest/gbi_extensions.h index 9e80461a..996e5376 100644 --- a/include/libforest/gbi_extensions.h +++ b/include/libforest/gbi_extensions.h @@ -553,6 +553,32 @@ do { \ (gsSPNTriangleData2(v0, v1, v2) << 1)) | G_VTX_MODE_7bit \ }} +#define gDPSetTexEdgeAlpha(pkt, alpha) \ +do { \ + Gfx* _g = (Gfx*)(pkt); \ + _g->words.w0 = (u32)(_SHIFTL(G_SETTEXEDGEALPHA, 24, 8)); \ + _g->words.w1 = (u32)(_SHIFTL(alpha, 0, 8)); \ +} while(0) + +#define gsDPSetTexEdgeAlpha(alpha) \ +{{ \ + (u32)(_SHIFTL(G_SETTEXEDGEALPHA, 24, 8)), \ + (u32)(_SHIFTL(alpha, 0, 8)) \ +}} + +#define gDPSetTextureAdjustMode(pkt, type, mode) \ +do { \ + Gfx* _g = (Gfx*)(pkt); \ + _g->words.w0 = (u32)(_SHIFTL(G_SPECIAL_1, 24, 8) | _SHIFTL(type, 16, 8) | _SHIFTL(mode, 0, 16)); \ + _g->words.w1 = (u32)0; \ +} while(0) + +#define gsDPSetTextureAdjustMode(type, mode) \ +{{ \ + (u32)(_SHIFTL(G_SPECIAL_1, 24, 8) | _SHIFTL(type, 16, 8) | _SHIFTL(mode, 0, 16)), \ + (u32)0 \ +}} + #ifdef __cplusplus } #endif diff --git a/include/m_all_grow.h b/include/m_all_grow.h index ead3bb70..a34045ad 100644 --- a/include/m_all_grow.h +++ b/include/m_all_grow.h @@ -2,12 +2,18 @@ #define M_ALL_GROW_H #include "types.h" +#include "m_field_info.h" #include "libu64/gfxprint.h" #ifdef __cplusplus extern "C" { #endif +#define mAGrw_DUMP_WIDTH 4 +#define mAGrw_DUMP_HEIGHT 4 + +extern void mAGrw_SearchDump(mFI_unit_c* dump_info); + extern void mAGrw_PrintFossilHaniwa_debug(gfxprint_t* gfxprint); #ifdef __cplusplus diff --git a/include/m_common_data.h b/include/m_common_data.h index 9bca2864..47137902 100644 --- a/include/m_common_data.h +++ b/include/m_common_data.h @@ -21,6 +21,7 @@ #include "m_needlework.h" #include "m_museum_display.h" #include "m_lib.h" +#include "m_field_assessment.h" #ifdef __cplusplus extern "C" { @@ -115,9 +116,11 @@ typedef struct Save_s { /* 0x022540 */ Island_c island; /* island data */ /* 0x023E40 */ u8 _tmp9[0x320]; /* 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[0x241A0 - 0x2416C]; + /* 0x02416C */ u8 _tmp10[0x24178 - 0x2416C]; + /* 0x024178 */ mFAs_GoodField_c good_field; /* field assessment last info */ + /* 0x024184 */ u8 _tmp11[0x241A0 - 0x24184]; /* 0x0241A0 */ lbRTC_time_c saved_auto_nwrite_time; /* save data notice time used for fishing tourney results? */ - /* 0x0241A8 */ u8 _tmp11[0x26000 - 0x241A8]; + /* 0x0241A8 */ u8 _tmp12[0x26000 - 0x241A8]; } Save_t; typedef union save_u { diff --git a/include/m_field_assessment.h b/include/m_field_assessment.h index da05ae60..19067fce 100644 --- a/include/m_field_assessment.h +++ b/include/m_field_assessment.h @@ -3,11 +3,50 @@ #include "types.h" #include "libu64/gfxprint.h" +#include "m_time.h" +#include "m_random_field_h.h" + #ifdef __cplusplus extern "C" { #endif +#define mFAs_PERFECT_DAY_STREAK_MAX 15 /* max number of perfect days in a row for golden axe reward */ + +#define mFAs_GRASS_OVER_NUM 5 +#define mFAs_DUST_OVER_NUM 5 +#define mFAs_FG_BLOCK_EXCLUDE_NUM 5 /* number of excluded block types */ +#define mFAs_TREE_RANK_COUNT 5 + +enum { + mFAs_FIELDRANK_ZERO, + mFAs_FIELDRANK_ONE, + mFAs_FIELDRANK_TWO, + mFAs_FIELDRANK_THREE, + mFAs_FIELDRANK_FOUR, + mFAs_FIELDRANK_FIVE, + mFAs_FIELDRANK_SIX, + + mFAs_FIELDRANK_NUM +}; + +enum { + mFAs_CONDITION_NONE = -1, + mFAs_CONDITION_DUST_OVER = 0, + mFAs_CONDITION_TREE_LESS, + mFAs_CONDITION_TREE_OVER, + mFAs_CONDITION_GRASS_OVER, + mFAs_CONDITION_NO_CASE, + + mFAs_CONDITION_NUM +}; + +/* sizeof(mFAs_GoodField_c) == 0xC */ +typedef struct good_field_s { + /* 0x00 */ lbRTC_time_c renew_time; /* time updated */ + /* 0x08 */ int perfect_day_streak; /* number of days in a row the town is "perfect" */ +} mFAs_GoodField_c; + extern void mFAs_PrintFieldAssessment(gfxprint_t* gfxprint); #ifdef __cplusplus diff --git a/include/m_field_info.h b/include/m_field_info.h index a0795e50..b86db481 100644 --- a/include/m_field_info.h +++ b/include/m_field_info.h @@ -55,10 +55,21 @@ enum { mFI_CLIMATE_NUM }; +/* sizeof(mFI_unit_c) == 0x14 */ +typedef struct location_info_s { + /* 0x00 */ int block_x; + /* 0x04 */ int block_z; + /* 0x08 */ int unit_x; + /* 0x0C */ int unit_z; + /* 0x10 */ mActor_name_t* block_data; +} mFI_unit_c; + +extern int mFI_CheckFieldData(); extern mActor_name_t mFI_GetFieldId(); extern int mFI_GetClimate(); extern mActor_name_t* mFI_BkNumtoUtFGTop(int block_x, int block_z); extern void mFI_ClearDeposit(int block_x, int block_z); +extern void mFI_GetSpecialBlockNum(int* block_pos_tbl, u32* kind_list, int kind_num); extern int mFI_SetTreasure(int* block_x, int* block_z, mActor_name_t item_no); extern void mFI_PrintNowBGNum(gfxprint_t* gfxprint); diff --git a/include/m_field_make.h b/include/m_field_make.h index a7124f69..9e745f9d 100644 --- a/include/m_field_make.h +++ b/include/m_field_make.h @@ -10,12 +10,21 @@ extern "C" { #define BLOCK_X_NUM 7 #define BLOCK_Z_NUM 10 +#define BLOCK_TOTAL_NUM (BLOCK_X_NUM * BLOCK_Z_NUM) #define FG_BLOCK_X_NUM (BLOCK_X_NUM - 2) /* 5 */ #define FG_BLOCK_Z_NUM (BLOCK_Z_NUM - 4) /* 6 */ +#define FG_BLOCK_TOTAL_NUM (FG_BLOCK_X_NUM * FG_BLOCK_Z_NUM) #define UT_X_NUM 16 /* Spaces per block (acre) in x direction */ #define UT_Z_NUM 16 /* Spaces per block (acre) in z direction */ +#define UT_TOTAL_NUM (UT_X_NUM * UT_Z_NUM) + +#define IDX_2_UT_X(idx) ((idx) & (UT_X_NUM - 1)) +#define IDX_2_UT_Z(idx) (((idx) / UT_X_NUM) & (UT_Z_NUM - 1)) + +#define FGIDX_2_BLOCK_X(idx) ((idx) % FG_BLOCK_X_NUM + 1) +#define FGIDX_2_BLOCK_Z(idx) ((idx) / FG_BLOCK_X_NUM + 1) /* sizeof(mFM_combination_c) == 2 */ typedef struct block_combination_s { diff --git a/include/m_lib.h b/include/m_lib.h index 8f8e881e..f73403e1 100644 --- a/include/m_lib.h +++ b/include/m_lib.h @@ -18,11 +18,11 @@ typedef struct xy_s { f32 x, y; } xy_t; -typedef struct xyz_t { +typedef struct xyz_s { f32 x, y, z; } xyz_t; -typedef struct s_xyz { +typedef struct s_xyz_s { s16 x, y, z; } s_xyz; diff --git a/include/m_name_table.h b/include/m_name_table.h index 95135397..858f2ad7 100644 --- a/include/m_name_table.h +++ b/include/m_name_table.h @@ -33,17 +33,208 @@ enum { /* Retrieve the item actor's category */ #define ITEM_NAME_GET_TYPE(n) (((n) & 0xF000) >> 12) +#define ITEM_NAME_GET_CAT(n) (((n) & 0x0F00) >> 8) #define ITEM_IS_FTR(n) \ (ITEM_NAME_GET_TYPE(n) == NAME_TYPE_FTR0 || ITEM_NAME_GET_TYPE(n) == NAME_TYPE_FTR1) #define ITEM_IS_ITEM1(n) (ITEM_NAME_GET_TYPE(n) == NAME_TYPE_ITEM1) -#define GET_NAME_ITEM0_CATEGORY(f) (((f) & 0x0800) >> 11) +#define GET_NAME_ITEM0_CATEGORY(f) (((f) & 0x0800) >> 11) /* enviornmental or static background objects */ #define GET_NAME_ITEM1_CATEGORY(f) (((f) & 0x0F00) >> 8) +#define IS_ITEM_FLOWER(item) ((item) >= FLOWER_LEAVES_PANSIES0 && (item) <= FLOWER_TULIP2) +#define IS_ITEM_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) || \ + ((item) == DEAD_SAPLING) || \ + ((item) == DEAD_PALM_SAPLING) || \ + ((item) == DEAD_CEDAR_SAPLING) || \ + ((item) == DEAD_GOLD_SAPLING) \ + ) + +#define IS_ITEM_GROWN_TREE(item) \ + (((item) == TREE) || \ + ((item) == TREE_1000BELLS) || \ + ((item) == TREE_10000BELLS) || \ + ((item) == TREE_30000BELLS) || \ + ((item) == TREE_100BELLS) || \ + ((item) == CEDAR_TREE) || \ + ((item) == GOLD_TREE_SHOVEL || (item) == GOLD_TREE) || \ + ((item) == TREE_APPLE_NOFRUIT_0 || (item) == TREE_APPLE_NOFRUIT_1 || (item) == TREE_APPLE_NOFRUIT_2 || (item) == TREE_APPLE_FRUIT) || \ + ((item) == TREE_ORANGE_NOFRUIT_0 || (item) == TREE_ORANGE_NOFRUIT_1 || (item) == TREE_ORANGE_NOFRUIT_2 || (item) == TREE_ORANGE_FRUIT) || \ + ((item) == TREE_PEACH_NOFRUIT_0 || (item) == TREE_PEACH_NOFRUIT_1 || (item) == TREE_PEACH_NOFRUIT_2 || (item) == TREE_PEACH_FRUIT) || \ + ((item) == TREE_PEAR_NOFRUIT_0 || (item) == TREE_PEAR_NOFRUIT_1 || (item) == TREE_PEAR_NOFRUIT_2 || (item) == TREE_PEAR_FRUIT) || \ + ((item) == TREE_CHERRY_NOFRUIT_0 || (item) == TREE_CHERRY_NOFRUIT_1 || (item) == TREE_CHERRY_NOFRUIT_2 || (item) == TREE_CHERRY_FRUIT) || \ + ((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) \ + ) + +#define IS_ITEM_GRASS(item) ((item) >= GRASS_A && (item) <= GRASS_C) /* aka IS_ITEM_WEED */ + +#define BG_CATEGORY 0 +#define ENV_CATEGORY 8 + #define EMPTY_NO 0x0000 +#define GRASS_A 0x0008 +#define GRASS_B (GRASS_A + 1) +#define GRASS_C (GRASS_B + 1) + +#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 CEDAR_TREE_BELLS 0x0078 +#define CEDAR_TREE_FTR (CEDAR_TREE_BELLS + 1) +#define CEDAR_TREE_BEES (CEDAR_TREE_FTR + 1) + +#define GOLD_TREE_BELLS 0x007F +#define GOLD_TREE_FTR (GOLD_TREE_BELLS + 1) +#define GOLD_TREE_BEES (GOLD_TREE_FTR + 1) +#define CEDAR_TREE_LIGHTS (GOLD_TREE_BEES + 1) + +/* begin environmental/nature objects */ +#define ENV_START 0x0800 +/* tree */ +#define TREE_SAPLING ENV_START +#define TREE_S0 (TREE_SAPLING + 1) +#define TREE_S1 (TREE_S0 + 1) +#define TREE_S2 (TREE_S1 + 1) +#define TREE (TREE_S2 + 1) /* fully grown */ +/* apple tree */ +#define TREE_APPLE_SAPLING (TREE + 1) +#define TREE_APPLE_S0 (TREE_APPLE_SAPLING + 1) +#define TREE_APPLE_S1 (TREE_APPLE_S0 + 1) +#define TREE_APPLE_S2 (TREE_APPLE_S1 + 1) +#define TREE_APPLE_NOFRUIT_0 (TREE_APPLE_S2 + 1) /* fully grown, no fruit */ +#define TREE_APPLE_NOFRUIT_1 (TREE_APPLE_NOFRUIT_0 + 1) +#define TREE_APPLE_NOFRUIT_2 (TREE_APPLE_NOFRUIT_1 + 1) +#define TREE_APPLE_FRUIT (TREE_APPLE_NOFRUIT_2 + 1) +/* orange tree */ +#define TREE_ORANGE_SAPLING (TREE_APPLE_FRUIT + 1) +#define TREE_ORANGE_S0 (TREE_ORANGE_SAPLING + 1) +#define TREE_ORANGE_S1 (TREE_ORANGE_S0 + 1) +#define TREE_ORANGE_S2 (TREE_ORANGE_S1 + 1) /* fully grown, no fruit */ +#define TREE_ORANGE_NOFRUIT_0 (TREE_ORANGE_S2 + 1) +#define TREE_ORANGE_NOFRUIT_1 (TREE_ORANGE_NOFRUIT_0 + 1) +#define TREE_ORANGE_NOFRUIT_2 (TREE_ORANGE_NOFRUIT_1 + 1) +#define TREE_ORANGE_FRUIT (TREE_ORANGE_NOFRUIT_2 + 1) +/* peach tree */ +#define TREE_PEACH_SAPLING (TREE_ORANGE_FRUIT + 1) +#define TREE_PEACH_S0 (TREE_PEACH_SAPLING + 1) +#define TREE_PEACH_S1 (TREE_PEACH_S0 + 1) +#define TREE_PEACH_S2 (TREE_PEACH_S1 + 1) +#define TREE_PEACH_NOFRUIT_0 (TREE_PEACH_S2 + 1) /* fully grown, no fruit */ +#define TREE_PEACH_NOFRUIT_1 (TREE_PEACH_NOFRUIT_0 + 1) +#define TREE_PEACH_NOFRUIT_2 (TREE_PEACH_NOFRUIT_1 + 1) +#define TREE_PEACH_FRUIT (TREE_PEACH_NOFRUIT_2 + 1) +/* pear tree */ +#define TREE_PEAR_SAPLING (TREE_PEACH_FRUIT + 1) +#define TREE_PEAR_S0 (TREE_PEAR_SAPLING + 1) +#define TREE_PEAR_S1 (TREE_PEAR_S0 + 1) +#define TREE_PEAR_S2 (TREE_PEAR_S1 + 1) +#define TREE_PEAR_NOFRUIT_0 (TREE_PEAR_S2 + 1) /* fully grown, no fruit */ +#define TREE_PEAR_NOFRUIT_1 (TREE_PEAR_NOFRUIT_0 + 1) +#define TREE_PEAR_NOFRUIT_2 (TREE_PEAR_NOFRUIT_1 + 1) +#define TREE_PEAR_FRUIT (TREE_PEAR_NOFRUIT_2 + 1) +/* cherry tree */ +#define TREE_CHERRY_SAPLING (TREE_PEAR_FRUIT + 1) +#define TREE_CHERRY_S0 (TREE_CHERRY_SAPLING + 1) +#define TREE_CHERRY_S1 (TREE_CHERRY_S0 + 1) +#define TREE_CHERRY_S2 (TREE_CHERRY_S1 + 1) +#define TREE_CHERRY_NOFRUIT_0 (TREE_CHERRY_S2 + 1) /* fully grown, no fruit */ +#define TREE_CHERRY_NOFRUIT_1 (TREE_CHERRY_NOFRUIT_0 + 1) +#define TREE_CHERRY_NOFRUIT_2 (TREE_CHERRY_NOFRUIT_1 + 1) +#define TREE_CHERRY_FRUIT (TREE_CHERRY_NOFRUIT_2 + 1) +/* money tree (1,000 Bells) */ +#define TREE_1000BELLS_SAPLING (TREE_CHERRY_FRUIT + 1) +#define TREE_1000BELLS_S0 (TREE_1000BELLS_SAPLING + 1) +#define TREE_1000BELLS_S1 (TREE_1000BELLS_S0 + 1) +#define TREE_1000BELLS_S2 (TREE_1000BELLS_S1 + 1) +#define TREE_1000BELLS (TREE_1000BELLS_S2 + 1) /* fully grown w/ bells */ +/* money tree (10,000 Bells) */ +#define TREE_10000BELLS_SAPLING (TREE_1000BELLS + 1) +#define TREE_10000BELLS_S0 (TREE_10000BELLS_SAPLING + 1) +#define TREE_10000BELLS_S1 (TREE_10000BELLS_S0 + 1) +#define TREE_10000BELLS_S2 (TREE_10000BELLS_S1 + 1) +#define TREE_10000BELLS (TREE_10000BELLS_S2 + 1) /* fully grown w/ bells */ +/* money tree (30,000 Bells) */ +#define TREE_30000BELLS_SAPLING (TREE_10000BELLS + 1) +#define TREE_30000BELLS_S0 (TREE_30000BELLS_SAPLING + 1) +#define TREE_30000BELLS_S1 (TREE_30000BELLS_S0 + 1) +#define TREE_30000BELLS_S2 (TREE_30000BELLS_S1 + 1) +#define TREE_30000BELLS (TREE_30000BELLS_S2 + 1) /* fully grown w/ bells */ +/* flower leaves (unused growth stage) */ +#define FLOWER_LEAVES_PANSIES0 (TREE_30000BELLS + 1) /* white */ +#define FLOWER_LEAVES_PANSIES1 (FLOWER_LEAVES_PANSIES0 + 1) /* purple */ +#define FLOWER_LEAVES_PANSIES2 (FLOWER_LEAVES_PANSIES1 + 1) /* yellow */ +#define FLOWER_LEAVES_COSMOS0 (FLOWER_LEAVES_PANSIES2 + 1) /* yellow */ +#define FLOWER_LEAVES_COSMOS1 (FLOWER_LEAVES_COSMOS0 + 1) /* purple */ +#define FLOWER_LEAVES_COSMOS2 (FLOWER_LEAVES_COSMOS1 + 1) /* blue */ +#define FLOWER_LEAVES_TULIP0 (FLOWER_LEAVES_COSMOS2 + 1) /* red */ +#define FLOWER_LEAVES_TULIP1 (FLOWER_LEAVES_TULIP0 + 1) /* white */ +#define FLOWER_LEAVES_TULIP2 (FLOWER_LEAVES_TULIP1 + 1) /* yellow */ +/* flowers */ +#define FLOWER_PANSIES0 (FLOWER_LEAVES_TULIP2 + 1) /* white */ +#define FLOWER_PANSIES1 (FLOWER_PANSIES0 + 1) /* purple */ +#define FLOWER_PANSIES2 (FLOWER_PANSIES1 + 1) /* yellow */ +#define FLOWER_COSMOS0 (FLOWER_PANSIES2 + 1) /* yellow */ +#define FLOWER_COSMOS1 (FLOWER_COSMOS0 + 1) /* purple */ +#define FLOWER_COSMOS2 (FLOWER_COSMOS1 + 1) /* blue */ +#define FLOWER_TULIP0 (FLOWER_COSMOS2 + 1) /* red */ +#define FLOWER_TULIP1 (FLOWER_TULIP0 + 1) /* white */ +#define FLOWER_TULIP2 (FLOWER_TULIP1 + 1) /* yellow */ +/* dead sapling */ +#define DEAD_SAPLING (FLOWER_TULIP2 + 1) +/* money tree (100 Bells) */ +#define TREE_100BELLS_SAPLING (DEAD_SAPLING + 1) +#define TREE_100BELLS_S0 (TREE_100BELLS_SAPLING + 1) +#define TREE_100BELLS_S1 (TREE_100BELLS_S0 + 1) +#define TREE_100BELLS_S2 (TREE_100BELLS_S1 + 1) +#define TREE_100BELLS (TREE_100BELLS_S2 + 1) /* fully grown w/ bells */ +/* palm tree */ +#define TREE_PALM_SAPLING (TREE_100BELLS + 1) +#define TREE_PALM_S0 (TREE_PALM_SAPLING + 1) +#define TREE_PALM_S1 (TREE_PALM_S0 + 1) +#define TREE_PALM_S2 (TREE_PALM_S1 + 1) +#define TREE_PALM_NOFRUIT_0 (TREE_PALM_S2 + 1) /* fully grown, no fruit */ +#define TREE_PALM_NOFRUIT_1 (TREE_PALM_NOFRUIT_0 + 1) +#define TREE_PALM_NOFRUIT_2 (TREE_PALM_NOFRUIT_1 + 1) +#define TREE_PALM_FRUIT (TREE_PALM_NOFRUIT_2 + 1) +#define DEAD_PALM_SAPLING (TREE_PALM_FRUIT + 1) +/* cedar tree */ +#define CEDAR_TREE_SAPLING (DEAD_PALM_SAPLING + 1) +#define CEDAR_TREE_S0 (CEDAR_TREE_SAPLING + 1) +#define CEDAR_TREE_S1 (CEDAR_TREE_S0 + 1) +#define CEDAR_TREE_S2 (CEDAR_TREE_S1 + 1) +#define CEDAR_TREE (CEDAR_TREE_S2 + 1) /* fully grown */ +#define DEAD_CEDAR_SAPLING (CEDAR_TREE + 1) +/* gold tree */ +#define GOLD_TREE_SAPLING (DEAD_CEDAR_SAPLING + 1) +#define GOLD_TREE_S0 (GOLD_TREE_SAPLING + 1) +#define GOLD_TREE_S1 (GOLD_TREE_S0 + 1) +#define GOLD_TREE_S2 (GOLD_TREE_S1 + 1) +#define GOLD_TREE_SHOVEL (GOLD_TREE_S2 + 1) /* fully grown w/ golden shovel */ +#define GOLD_TREE (GOLD_TREE_SHOVEL + 1) /* fully grown */ +#define DEAD_GOLD_SAPLING (GOLD_TREE + 1) +/* end of environmental objects */ + #define FTR_REDALOHASHIRT 0x1814 #define FTR_BLUEALOHASHIRT 0x1818 @@ -55,6 +246,9 @@ enum { #define ITM_SHOVEL 0x2202 #define ITM_ROD 0x2203 +#define ITM_DUST0_EMPTY_CAN 0x250E +#define ITM_DUST1_BOOT 0x250F +#define ITM_DUST2_OLD_TIRE 0x2510 #define ITM_PITFALL 0x2512 #define ITM_ENV_START 0x2900 diff --git a/include/m_random_field_h.h b/include/m_random_field_h.h new file mode 100644 index 00000000..e6b55179 --- /dev/null +++ b/include/m_random_field_h.h @@ -0,0 +1,48 @@ +#ifndef M_RANDOM_FIELD_H +#define M_RANDOM_FIELD_H + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define mRF_BLOCKKIND_NONE (0 << 0) +#define mRF_BLOCKKIND_PLAYER (1 << 0) +#define mRF_BLOCKKIND_SHOP (1 << 1) +#define mRF_BLOCKKIND_SHRINE (1 << 2) +#define mRF_BLOCKKIND_POLICE (1 << 3) +#define mRF_BLOCKKIND_POSTOFFICE (1 << 4) +#define mRF_BLOCKKIND_STATION (1 << 5) +#define mRF_BLOCKKIND_CLIFF (1 << 6) +#define mRF_BLOCKKIND_RIVER (1 << 7) +#define mRF_BLOCKKIND_WATERFALL (1 << 8) +#define mRF_BLOCKKIND_BRIDGE (1 << 9) +#define mRF_BLOCKKIND_RAILROAD (1 << 10) +#define mRF_BLOCKKIND_BEACH (1 << 11) +#define mRF_BLOCKKIND_BORDER (1 << 12) +#define mRF_BLOCKKIND_TUNNEL (1 << 13) +#define mRF_BLOCKKIND_SLOPE (1 << 14) +#define mRF_BLOCKKIND_POOL (1 << 15) +#define mRF_BLOCKKIND_DUMP (1 << 16) +#define mRF_BLOCKKIND_MUSEUM (1 << 17) +#define mRF_BLOCKKIND_18 (1 << 18) +#define mRF_BLOCKKIND_TAILORS (1 << 19) +#define mRF_BLOCKKIND_OCEAN (1 << 20) +#define mRF_BLOCKKIND_ISLAND_RIGHT (1 << 21) +#define mRF_BLOCKKIND_OFFING (1 << 22) +#define mRF_BLOCKKIND_23 (1 << 23) +#define mRF_BLOCKKIND_24 (1 << 24) +#define mRF_BLOCKKIND_25 (1 << 25) +#define mRF_BLOCKKIND_26 (1 << 26) +#define mRF_BLOCKKIND_27 (1 << 27) +#define mRF_BLOCKKIND_28 (1 << 28) +#define mRF_BLOCKKIND_29 (1 << 29) +#define mRF_BLOCKKIND_DOCK (1 << 30) +#define mRF_BLOCKKIND_ISLAND_LEFT (1 << 31) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rel/m_field_assessment.c b/rel/m_field_assessment.c new file mode 100644 index 00000000..cd725087 --- /dev/null +++ b/rel/m_field_assessment.c @@ -0,0 +1,527 @@ +#include "m_field_assessment.h" +#include "m_field_info.h" +#include "m_name_table.h" +#include "m_common_data.h" +#include "m_all_grow.h" +#include "libultra/libultra.h" +#include "libc64/qrand.h" + +static int l_good_block_num; +static int l_field_assessment_rank; + +static void mFAs_ClearGoodField_common(mFAs_GoodField_c* good_field) { + lbRTC_TimeCopy(&good_field->renew_time, &mTM_rtcTime_clear_code); + good_field->perfect_day_streak = 0; +} + +extern void mFAs_ClearGoodField() { + mFAs_ClearGoodField_common(Save_GetPointer(good_field)); +} + +extern int mFAs_CheckGoodField() { + int res = FALSE; + if (Save_Get(good_field.perfect_day_streak) >= mFAs_PERFECT_DAY_STREAK_MAX) { + res = TRUE; + } + + return res; +} + +static void mFAs_SetGoodField(int rank) { + mFAs_GoodField_c* good_field = Save_GetPointer(good_field); + lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time); + if (rank == mFAs_FIELDRANK_SIX) { + if (mTM_IsTimeEqual(&mTM_rtcTime_clear_code, &good_field->renew_time) == TRUE) { + lbRTC_TimeCopy(&good_field->renew_time, rtc_time); + good_field->perfect_day_streak = 0; + } + else { + if (lbRTC_IsOverTime(&good_field->renew_time, rtc_time) == lbRTC_OVER) { + int day_interval = lbRTC_GetIntervalDays(&good_field->renew_time, rtc_time); + if (day_interval > 0) { + lbRTC_TimeCopy(&good_field->renew_time, rtc_time); + if (good_field->perfect_day_streak + day_interval > mFAs_PERFECT_DAY_STREAK_MAX) { + good_field->perfect_day_streak = mFAs_PERFECT_DAY_STREAK_MAX; + } + else { + good_field->perfect_day_streak += day_interval; + } + } + } + else { + lbRTC_TimeCopy(&good_field->renew_time, rtc_time); + good_field->perfect_day_streak = 0; + } + } + } + else { + mFAs_ClearGoodField_common(good_field); + } +} + +static int mFAs_GetIdx(u8* points_by_rank, u8 total_points, int ranks_count) { + int res = -1; + int i; + + for (i = 0; i < ranks_count; i++) { + if (total_points <= *points_by_rank) { + res = i; + break; + } + + points_by_rank++; + } + + return res; +} + +static int mFAs_CheckDust(mActor_name_t item) { + int res = FALSE; + + if (item == ITM_DUST0_EMPTY_CAN || item == ITM_DUST1_BOOT || item == ITM_DUST2_OLD_TIRE) { + res = TRUE; + } + + return res; +} + +static int mFAs_GetBlockTreeNum2( + int* tree_num, /* trees */ + int* flower_num, /* flowers */ + int* effective_grass_num, /* weeds - flowers */ + int* total_grass_num, /* weeds */ + int* dust_num, /* trash not in dump */ + mFI_unit_c* dump_unit_info, /* dump location */ + mActor_name_t* block_items, /* items in acre */ + int block_item_count /* item count */ +) { + int trees; + int i; + + trees = 0; + for (i = 0; i < block_item_count; i++) { + mActor_name_t item = *block_items; + if (ITEM_NAME_GET_TYPE(item) == NAME_TYPE_ITEM0) { + int category = ITEM_NAME_GET_CAT(item); + if (category == ENV_CATEGORY) { + if (IS_ITEM_FLOWER(item)) { + (*flower_num)++; + } + else if (IS_ITEM_TREE(item)) { + trees++; + } + } + else if (category == BG_CATEGORY) { + if (IS_ITEM_GRASS(item)) { + (*effective_grass_num)++; + } + // IS_ITEM_GROWN_TREE is unnecessary here, as the majority of the conditional checks are impossible + // They should've just checked the special trees that live in the "BG" range + else if (IS_ITEM_GROWN_TREE(item)) { + trees++; + } + } + } + else if (mFAs_CheckDust(item) == TRUE) { + int ut_x = IDX_2_UT_X(i); + int ut_z = IDX_2_UT_Z(i); + if ((dump_unit_info == NULL) || + (dump_unit_info->block_data == NULL) || + (dump_unit_info->unit_x < ut_x || dump_unit_info->unit_x - mAGrw_DUMP_WIDTH > ut_x) || + (dump_unit_info->unit_z < ut_z || dump_unit_info->unit_z - mAGrw_DUMP_HEIGHT > ut_z) + ) { + (*dust_num)++; /* trash outside of dump */ + } + } + + block_items++; + } + + *tree_num = trees; + *total_grass_num = *effective_grass_num; + *effective_grass_num -= *flower_num; /* offset weeds by number of flowers */ + return trees; +} + +static u8 l_block_rank_tree_num[mFAs_TREE_RANK_COUNT] = { 8, 11, 14, 17, 255 }; + +/* int tree_num, int grass_num */ +typedef int (*mFAs_CheckProc)(int, int); + +static int mFAs_CheckDustOver(int tree_num, int grass_num) { + return FALSE; +} + +static int mFAs_CheckTreeLess(int tree_num, int grass_num) { + return tree_num <= l_block_rank_tree_num[0]; +} + +static int mFAs_CheckTreeOver(int tree_num, int grass_num) { + return tree_num >= l_block_rank_tree_num[3]; +} + +static int mFAs_CheckGrassOver(int tree_num, int grass_num) { + return grass_num >= mFAs_GRASS_OVER_NUM; +} + +static int mFAs_CheckNoCase() { + return FALSE; +} + +static int mFAs_CheckCondition(int* condition_num, int tree_num, int grass_num) { + static mFAs_CheckProc bk_chk[mFAs_CONDITION_NUM] = { + &mFAs_CheckDustOver, + &mFAs_CheckTreeLess, + &mFAs_CheckTreeOver, + &mFAs_CheckGrassOver, + &mFAs_CheckNoCase + }; + + int check; + + for (check = 0; check <= *condition_num; check++) { + if ((*bk_chk[check])(tree_num, grass_num) == TRUE) { + return check; /* current mFAs_CONDITION_* exists */ + } + } + + return -1; /* no issue */ +} + +static int mFAs_CheckBlockNum(int* block_num, int block_x, int block_z, int failed_condition) { + int res = TRUE; + + /* check if the failed condition is within a non-excluded acre */ + if (block_num != NULL && failed_condition <= mFAs_CONDITION_TREE_OVER) { + if (block_z == FG_BLOCK_Z_NUM) { + res = FALSE; + } + else { + int x; + for (x = 0; x < mFAs_FG_BLOCK_EXCLUDE_NUM; x++) { + if (block_x == block_num[0] && block_z == block_num[1]) { + res = FALSE; + break; + } + + block_num += 2; + } + } + } + + return res; +} + +static u8 l_block_rank_table[mFAs_TREE_RANK_COUNT] = { 0, 1, 2, 1, 0 }; +static u8 l_block_max_by_rank[mFAs_FIELDRANK_NUM] = { 0, 2, 4, 7, 12, 16, 255 }; +static int l_mfas_romf_check[5] = { 0, 0, 0, 0, 0 }; + +#pragma pool_data on +/* TODO: @nonmatching */ +static int mFAs_GetFieldGoodBlockNum_common(int* condition_num, int* block_x, int* block_z, int* block_num) { + int set_bad_block = FALSE; + mFI_unit_c dump_unit; + int perfect_block_num = 0; + mFM_fg_c* fg_block_items; + int bx, bz; + int condition_result; + int good_blocks = 0; + int flower_num; + int block_dust_num; + int total_flowers = 0; + int i; + int selected_block_x = 0; + int selected_block_z = 0; + int tree_num = 0; + int grass_num = 0; + int effective_grass_num = 0; + int total_trees = 0; + int total_grass = 0; + int rank; + int good_block_num; + mFI_unit_c* dump_info; + int trees; + int dust_num = 0; + + dump_unit.block_data = (void*)(set_bad_block); + dump_info = (void*)(set_bad_block); + fg_block_items = Save_GetPointer(fg[0][0]); + + if (mFI_CheckFieldData()) { + mAGrw_SearchDump(&dump_unit); + } + + for (i = 0; i < FG_BLOCK_TOTAL_NUM; i++) { + block_dust_num = 0; + tree_num = 0; + effective_grass_num = 0; + grass_num = 0; + flower_num = 0; + bx = 1 + (i % 5); + bz = 1 + (i / 5); + + if (dump_unit.block_data != NULL && dump_unit.block_x == bx && dump_unit.block_z == bz) { + dump_info = &dump_unit; + } + else { + dump_info = NULL; + } + + trees = mFAs_GetBlockTreeNum2(&tree_num, &flower_num, &effective_grass_num, &grass_num, &block_dust_num, dump_info, (mActor_name_t*)fg_block_items->items, UT_TOTAL_NUM); + dust_num += block_dust_num; + + if (condition_num != NULL) { + condition_result = mFAs_CheckCondition(condition_num, tree_num, effective_grass_num); + if (condition_result != mFAs_CONDITION_NONE && mFAs_CheckBlockNum(block_num, bx, bz, condition_result) == TRUE) { + if (condition_result != *condition_num) { + *condition_num = condition_result; + condition_result = 1; + } + else { + condition_result = (fqrand() * 3.0f); + } + + if (condition_result == 1 && block_x != NULL && block_z != NULL) { + *block_x = bx; + *block_z = bz; + } + } + } + + if (block_dust_num != 0) { + // bug here? this only executes when the value is not FALSE, but value is only + // updated within the if statement block. + if (!set_bad_block) { + selected_block_x = bx; + selected_block_z = bz; + + #ifdef BUGFIXES + set_bad_block = TRUE; + #endif + } + else { + if ((int)(fqrand() * 3.0f) == 1) { + selected_block_x = bx; + selected_block_z = bz; + } + #ifndef BUGFIXES + set_bad_block = TRUE; + #endif + } + + rank = 0; + } + else { + if (effective_grass_num >= 3) { + rank = 0; /* 0 points if there are 3 or more weeds in a single acre */ + } + else { + rank = l_block_rank_table[mFAs_GetIdx(l_block_rank_tree_num, trees, mFAs_TREE_RANK_COUNT)]; + } + } + + if (rank == 2) { + perfect_block_num++; + } + else if (rank == 1) { + good_blocks++; + } + + total_trees += tree_num; + total_flowers += flower_num; + total_grass += grass_num; + fg_block_items++; + } + + l_mfas_romf_check[1] = FG_BLOCK_TOTAL_NUM - (good_blocks + perfect_block_num); /* "bad" block count */ + good_block_num = perfect_block_num + good_blocks / 2; + l_mfas_romf_check[0] = good_blocks; + l_mfas_romf_check[2] = total_trees; + l_mfas_romf_check[3] = total_flowers; + l_mfas_romf_check[4] = total_grass; + + if (dust_num >= mFAs_DUST_OVER_NUM) { + good_block_num = 0; + Save_Set(dust_flag, TRUE); + if (condition_num != NULL) { + *condition_num = mFAs_CONDITION_DUST_OVER; + } + + if (block_x != NULL && block_z != NULL) { + *block_x = selected_block_x; + *block_z = selected_block_z; + } + } + + if (condition_num != NULL && *condition_num != mFAs_CONDITION_NO_CASE) { + mFAs_ClearGoodField(); /* reset perfect town streak */ + } + + return good_block_num; +} +#pragma pool_data reset + +static int mFAs_GetFieldGoodBlockNum() { + int block_x = 0; + int block_z = 0; + + return mFAs_GetFieldGoodBlockNum_common(NULL, &block_x, &block_z, NULL); +} + +static int mFAs_GetFieldRankbyFGoodBlock(u8 good_block_num) { + return mFAs_GetIdx(l_block_max_by_rank, good_block_num, mFAs_FIELDRANK_NUM); +} + +/* TODO: @fake match */ +static int mFAs_GetDustNum(int* block_x, int* block_z) { + int set_bad_block; + mFM_fg_c* fg_block_items; + mActor_name_t* items; + int dust_num; + int block_dust_num; + int bz, bx; + int ut_z, ut_x; + int dump_ut_z, dump_ut_x; + int i; + mFI_unit_c dump_unit; + + dust_num = 0; + dump_unit.block_data = (void*)(set_bad_block = FALSE); // horrible hack + fg_block_items = Save_GetPointer(fg[0][0]); + + if (mFI_CheckFieldData()) { + mAGrw_SearchDump(&dump_unit); + } + + for (bz = 0; bz < FG_BLOCK_Z_NUM; bz++) { + for (bx = 0; bx < FG_BLOCK_X_NUM; bx++) { + block_dust_num = 0; + + if (fg_block_items != NULL) { + items = (mActor_name_t*)fg_block_items->items; + if (dump_unit.block_data != NULL && bx + 1 == dump_unit.block_x && bz + 1 == dump_unit.block_z) { + // we're in the dump acre so check if the trash is in the dump bounds + for (ut_z = 0; ut_z < UT_Z_NUM; ut_z++) { + for (ut_x = 0; ut_x < UT_X_NUM; ut_x++) { + dump_ut_z = dump_unit.unit_z; + // surely the variable assignment within the if condition is wrong? + if ((ut_z < (dump_ut_z - mAGrw_DUMP_HEIGHT) || (ut_z > dump_ut_z)) || ((dump_ut_x = dump_unit.unit_x), ut_x < (dump_ut_x - mAGrw_DUMP_WIDTH)) || (ut_x > dump_ut_x)) { + if (mFAs_CheckDust(*items) == TRUE) { + dust_num++; + block_dust_num++; + } + } + items++; + } + } + } + else { + for (ut_z = 0; ut_z < UT_TOTAL_NUM; ut_z++) { + if (mFAs_CheckDust(*items) == TRUE) { + dust_num++; + block_dust_num++; + } + items++; + } + } + } + + if (block_dust_num != 0) { + if (!set_bad_block) { + *block_x = bx + 1; + *block_z = bz + 1; + + #ifdef BUGFIXES + set_bad_block = TRUE; + #endif + } + else { + if ((int)(fqrand() * 3.0f) == 1) { + *block_x = bx + 1; + *block_z = bz + 1; + } + + #ifndef BUGFIXES + set_bad_block = TRUE; + #endif + } + } + + fg_block_items++; + } + } + + return dust_num; +} + +extern int mFAs_GetFieldRank_Condition(int* rank, int* block_x, int* block_z) { + static u32 block_kind[mFAs_FG_BLOCK_EXCLUDE_NUM] = { + mRF_BLOCKKIND_SHRINE, + mRF_BLOCKKIND_POOL, + mRF_BLOCKKIND_STATION, + mRF_BLOCKKIND_PLAYER, + mRF_BLOCKKIND_MUSEUM + }; + + int block_pos_tbl[2 * mFAs_FG_BLOCK_EXCLUDE_NUM]; + int condition = mFAs_CONDITION_NO_CASE; + + *block_x = 0; + *block_z = 0; + bzero(block_pos_tbl, 2 * mFAs_FG_BLOCK_EXCLUDE_NUM * sizeof(int)); + mFI_GetSpecialBlockNum(block_pos_tbl, block_kind, mFAs_FG_BLOCK_EXCLUDE_NUM); + + if (Save_Get(dust_flag) == TRUE) { + if (mFAs_GetDustNum(block_x, block_z) == FALSE) { + Save_Set(dust_flag, FALSE); + } + else { + condition = mFAs_CONDITION_DUST_OVER; // trash still exists in acre + } + + l_good_block_num = 0; + } + + if (Save_Get(dust_flag) == FALSE) { + l_good_block_num = mFAs_GetFieldGoodBlockNum_common(&condition, block_x, block_z, block_pos_tbl); + } + + l_field_assessment_rank = mFAs_GetFieldRankbyFGoodBlock(l_good_block_num); + *rank = l_field_assessment_rank; + mFAs_SetGoodField(l_field_assessment_rank); + return condition; +} + +extern void mFAs_SetFieldRank() { + int bx, bz; + if (Save_Get(dust_flag) == TRUE) { + if (mFAs_GetDustNum(&bx, &bz) == FALSE) { + Save_Set(dust_flag, FALSE); + } + + l_good_block_num = 0; + } + + if (Save_Get(dust_flag) == FALSE) { + l_good_block_num = mFAs_GetFieldGoodBlockNum(); + } + + l_field_assessment_rank = mFAs_GetFieldRankbyFGoodBlock(l_good_block_num); + mFAs_SetGoodField(l_field_assessment_rank); +} + +extern int mFAs_GetFieldRank() { + return l_field_assessment_rank; +} + +#pragma pool_data on +extern void mFAs_PrintFieldAssessment(gfxprint_t* gfxprint) { + gfxprint_color(gfxprint, 240, 50, 150, 255); + gfxprint_locate8x8(gfxprint, 3, 14); + gfxprint_printf(gfxprint, "%04d %04d %04d", l_mfas_romf_check[2], l_mfas_romf_check[3], l_mfas_romf_check[4]); /* total trees, total flowers, total weeds(grass) */ + gfxprint_locate8x8(gfxprint, 3, 15); + gfxprint_printf(gfxprint, " %02d %02d %02d", l_good_block_num, l_mfas_romf_check[0], l_mfas_romf_check[1]); /* total good acres, 'ok' acres, 'bad' acres */ + gfxprint_locate8x8(gfxprint, 3, 16); + gfxprint_printf(gfxprint, " %02d", l_field_assessment_rank); /* current field rank */ +} +#pragma pool_data reset