Implement & link m_huusui_room.c, m_huusui_room_ovl.c

This commit is contained in:
Cuyler36
2023-04-27 18:44:33 -04:00
parent e3fee9e8f3
commit 6cb66bc773
13 changed files with 1771 additions and 25 deletions
+6
View File
@@ -4,6 +4,8 @@ m_debug_hayakawa.c:
.text: [0x803965E4, 0x803973E8]
.rodata: [0x80641D50, 0x80641D90]
.data: [0x80651328, 0x80651358]
m_huusui_room.c:
.text: [0x803B1908, 0x803B1968]
m_home.c:
.text: [0x803B2E88, 0x803B3688]
.data: [0x806546C8, 0x80655340]
@@ -60,6 +62,10 @@ zurumode.c:
sys_ucode.c:
.text: [0x8040F008, 0x8040F048]
.data: [0x8065FA30, 0x8065FA40]
m_huusui_room_ovl.c:
.text: [0x804D1BBC, 0x804D2164]
.rodata: [0x80646558, 0x806465C8]
.data: [0x8069C0F0, 0x8069CAF0]
m_random_field/mRF_MakePerfectBit.c:
.text: [0x8050B1AC, 0x8050B1D4]
m_random_field/mRF_GetRandomStepMode.c:
+1
View File
@@ -20892,6 +20892,7 @@ global:
0x8069C078: Room_Sunshine_Posthouse_Profile
0x8069C0A0: Room_Sunshine_Museum_Profile
0x8069C0C8: Room_Sunshine_Minsect_Profile
0x8069C0F0: mMkRm_ftr_info # this one lives in m_huusui_room_ovl.c
0x8069CAD4: mHsRm_unit_max
0x8069CAE4: mHsRm_unit_value
0x8069CAF0: mMkRm_series_info
+3
View File
@@ -106,6 +106,9 @@ typedef struct common_data_s {
/* 0x026110 */ Time_c time;
/* 0x02613C */ Private_c* now_private;
/* 0x026140 */ mHm_hs_c* now_home;
/* 0x026144 */ u8 tmp0[0x23E8];
/* 0x02852C */ s16 money_power;
/* 0x02852E */ s16 goods_power;
} common_data_t;
extern common_data_t common_data;
+2
View File
@@ -8,6 +8,8 @@
extern "C" {
#endif
extern int mEv_CheckFirstJob();
extern void mEv_debug_print4f(gfxprint_t* gfxprint);
extern void mEv_sp_debug_print4f(gfxprint_t* gfxprint);
+72
View File
@@ -0,0 +1,72 @@
#ifndef M_HUUSUI_ROOM_H
#define M_HUUSUI_ROOM_H
#include "types.h"
#include "game.h"
#include "m_private.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Feng Shui related functions
*
* Brief overview of how Feng Shui works:
* Money Power: increased money "luck"
* Goods power: increased item "luck"
*
* Feng Shui Colors:
* - NONE: no bonus
* - YELLOW: money power bonus on west side (+4)
* - RED: goods power bonus on east side (+4)
* - ORANGE: money & goods power bonuses on north side (+2 each)
* - GREEN: money & goods power bonuses on south side (+2 each)
* - LUCKY: money & goods power anywhere in house (+4 each)
*
* Feng Shui directional bonuses will only apply if all units
* of the furniture are in the same directional category. For
* example, if a green table (2x2) only has two units of its
* four unit total in the south direction, you will NOT get
* a bonus. Additionally, the smallest level house only has
* one unit columns/rows for Feng Shui while all other rooms
* have two columns/rows. This means that you can never get
* a Feng Shui bonus from 2x2 furniture in the smallest house.
*
* There is also a 'doll'/'face' deduction. If you rotate furniture
* marked as a doll/has_face towards the wall which is is adjacent to,
* you will get a -5 point luck penalty. This happens even when the
* Feng Shui type of the furniture is 'NONE'.
**/
#define mHsRm_GOODS_POWER_MAX 40
/* Feng Shui colors */
enum {
mHsRm_HUUSUI_NONE,
mHsRm_HUUSUI_YELLOW,
mHsRm_HUUSUI_RED,
mHsRm_HUUSUI_ORANGE,
mHsRm_HUUSUI_GREEN,
mHsRm_HUUSUI_LUCKY,
mHsRm_HUUSUI_NUM
};
/* Feng Shui house room directions */
enum {
mHsRm_DIRECTION_SOUTH,
mHsRm_DIRECTION_EAST,
mHsRm_DIRECTION_NORTH,
mHsRm_DIRECTION_WEST,
mHsRm_DIRECTION_NUM
};
extern void mHsRm_GetHuusuiRoom(GAME* game, int player_no);
#ifdef __cplusplus
}
#endif
#endif
+16
View File
@@ -0,0 +1,16 @@
#ifndef M_HUUSUI_ROOM_OVL_H
#define M_HUUSUI_ROOM_OVL_H
#include "types.h"
#ifdef __cplusplus
extern "C" {
#endif
extern void mHsRm_HuusuiRoomOvl(int player_no);
#ifdef __cplusplus
}
#endif
#endif
+30
View File
@@ -10,6 +10,36 @@
extern "C" {
#endif
enum {
NAME_TYPE_ITEM0, /* Scenery items */
NAME_TYPE_FTR0, /* Furniture 0 */
NAME_TYPE_ITEM1, /* Obtainable items */
NAME_TYPE_FTR1, /* Furniture 1 */
NAME_TYPE_WARP, /* Loading zones */
NAME_TYPE_STRUCT, /* Structures */
NAME_TYPE_PAD6, /* Unused? */
NAME_TYPE_PAD7, /* Unused? */
NAME_TYPE_ITEM2, /* Misc items */
NAME_TYPE_ACTOR, /* Actors */
NAME_TYPE_PROPS, /* Props */
NAME_TYPE_PADB, /* Unused? */
NAME_TYPE_PADC, /* Unused? */
NAME_TYPE_SPNPC, /* Special NPCs */
NAME_TYPE_NPC, /* Villager NPCs */
NAME_TYPE_PAD15, /* Unused? */
NAME_TYPE_NUM
};
/* Retrieve the item actor's category */
#define ITEM_NAME_GET_TYPE(n) (((n) & 0xF000) >> 12)
#define ITEM_IS_FTR(n) \
(ITEM_NAME_GET_TYPE(n) == NAME_TYPE_FTR0 || ITEM_NAME_GET_TYPE(n) == NAME_TYPE_FTR1)
#define GET_NAME_ITEM0_CATEGORY(f) (((f)&0x800) >> 11)
#define GET_NAME_ITEM1_CATEGORY(f) (((f)&0xF00) >> 8)
#define EMPTY_NO 0x0000
#define FTR_REDALOHASHIRT 0x1814
+13
View File
@@ -15,6 +15,19 @@ extern "C" {
#endif
#define PLAYER_NUM 4
#define FOREIGNER_NUM 1
#define TOTAL_PLAYER_NUM (PLAYER_NUM + FOREIGNER_NUM)
enum {
mPr_PLAYER_0,
mPr_PLAYER_1,
mPr_PLAYER_2,
mPr_PLAYER_3,
mPr_FOREIGNER,
mPr_PLAYER_NUM
};
#define mPr_POCKETS_SLOT_COUNT 15
#define mPr_INVENTORY_MAIL_COUNT 10
#define mPr_DELIVERY_QUEST_NUM mPr_POCKETS_SLOT_COUNT
+26 -21
View File
@@ -3,27 +3,33 @@
#include "types.h"
#include "libu64/gfxprint.h"
#include "m_actor_type.h"
#define mRmTp_FTR_UNIT_MAX 4
enum {
FG_ITEM0_TYPE,
FG_FTR0_TYPE,
FG_ITEM1_TYPE,
FG_FTR1_TYPE,
FG_NXGT0_TYPE,
FG_STRUCTURE_TYPE,
FG_PAD6_TYPE,
FG_PAD7_TYPE,
FG_ITEM2_TYPE,
FG_ACTOR_TYPE,
FG_PROPS_TYPE,
FG_PAD11_TYPE,
FG_PAD12_TYPE,
FG_SP_NPC_TYPE,
FG_NPC_TYPE,
FG_DONT_TYPE,
FG_TYPE_NUM
mRmTp_FTRSIZE_1x1, /* x */
mRmTp_FTRSIZE_1x2, /* yy OR y */
/* y */
mRmTp_FTRSIZE_2x2, /* zz */
/* zz */
mRmTp_FTRSIZE_NUM
};
typedef struct room_type_place_info_one_s {
int exists;
int ut_x;
int ut_z;
} mRmTp_FtrPlaceInfoOne_t;
typedef struct room_type_place_info_s {
mRmTp_FtrPlaceInfoOne_t units[mRmTp_FTR_UNIT_MAX];
} mRmTp_FtrPlaceInfo_t;
#define FTR_NUM 1266
#define FTR_GET_ROTATION(f) ((f) & 3)
// TEMPORARY. Should be generated with .decl files
#define ITEM0_NO_START 0x0000
#define NULL_NO ITEM0_NO_START
@@ -51,11 +57,10 @@ enum {
#define FTR1_NO_START 0x3000
#define GET_FG_ITEM0_CATEGORY(f) (((f)&0x800) >> 11)
#define GET_FG_ITEM1_CATEGORY(f) (((f)&0xF00) >> 8)
#define GET_FG_TYPE(f) (((f)&0xF000) >> 12)
extern void mRmTp_DrawFamicomInfo(gfxprint_t* gfxprint);
extern void mRmTp_MakeFamicom_Fdebug();
extern int mRmTp_FtrItemNo2FtrIdx(mActor_name_t ftr_item_no);
extern int mRmTp_GetFurnitureData(mActor_name_t ftr, int ut_x, int ut_z, mRmTp_FtrPlaceInfo_t* place_info);
#endif
+24
View File
@@ -0,0 +1,24 @@
#include "m_huusui_room.h"
#include "m_huusui_room_ovl.h"
#include "game.h"
#include "m_private.h"
#include "m_event.h"
#include "m_common_data.h"
/**
* @brief Main Feng Shui scoring entrypoint. Originally meant to live in code always.
*
* @param game Unused GAME pointer
* @param player_no The index of the player whose house will be scored for Feng Shui
**/
extern void mHsRm_GetHuusuiRoom(GAME* game, int player_no) {
/* Do not calculate Feng Shui if the player is doing chores or is from another town */
if (mEv_CheckFirstJob() == FALSE && player_no != mPr_FOREIGNER) {
mHsRm_HuusuiRoomOvl(player_no);
}
else {
Common_Set(money_power, 0);
Common_Set(goods_power, 0);
}
}
+309
View File
@@ -0,0 +1,309 @@
#include "m_huusui_room_ovl.h"
#include "m_huusui_room.h"
#include "m_actor_type.h"
#include "m_room_type.h"
#include "m_house.h"
#include "m_home_h.h"
#include "m_common_data.h"
#include "m_name_table.h"
#define mHsRm_UNIT_MAX_S 6
#define mHsRm_UNIT_MAX_M 8
#define mHsRm_UNIT_MAX_L 10
#define mHsRm_UNIT_MAX_UPPER mHsRm_UNIT_MAX_M
#define mHsRm_UNIT_MAX_BASEMENT mHsRm_UNIT_MAX_L
#define mHsRm_MONEY_LUCKY_PTS 4
#define mHsRm_GOODS_LUCKY_PTS 8
#define mHsRm_MONEY_BAD_PTS 10
#define mHsRm_GOODS_BAD_PTS 5
typedef struct huusui_room_ftr_info_s {
u8 huusui_type;
u8 has_face;
} mHsRm_ftr_info_c;
/* table of feng shui data for every item, clearly copy-pasted... should be mHsRm_ftr_info */
static mHsRm_ftr_info_c mMkRm_ftr_info[FTR_NUM] = {
#include "../rel/m_huusui_room_ovl_data.inc" /* data moved out of file due to length */
};
/* maximum unit position for each main floor size */
static int mHsRm_unit_max[mHm_HOMESIZE_NUM - 1] = {
mHsRm_UNIT_MAX_S, /* mHm_HOMESIZE_SMALL */
mHsRm_UNIT_MAX_M, /* mHm_HOMESIZE_MEDIUM */
mHsRm_UNIT_MAX_L, /* mHm_HOMESIZE_LARGE */
mHsRm_UNIT_MAX_L /* mHm_HOMESIZE_UPPER */
};
/* number of units taken up by each furniture size */
static int mHsRm_unit_value[mRmTp_FTRSIZE_NUM] = {
1, /* mRmTp_FTRSIZE_1x1 */
2, /* mRmTp_FTRSIZE_1x2 */
4 /* mRmTp_FTRSIZE_2x2 */
};
/* table indices below are [directions][points] */
#define mHsRm_WALL_NON (0) /* No wall */
#define mHsRm_WALL_STH (1 << mHsRm_DIRECTION_SOUTH) /* South wall */
#define mHsRm_WALL_EST (1 << mHsRm_DIRECTION_EAST) /* East wall */
#define mHsRm_WALL_NTH (1 << mHsRm_DIRECTION_NORTH) /* North wall */
#define mHsRm_WALL_WST (1 << mHsRm_DIRECTION_WEST) /* West wall */
#define mHsRm_WALL_ALL \
(mHsRm_WALL_STH | mHsRm_WALL_EST | mHsRm_WALL_NTH | mHsRm_WALL_WST) /* any wall */
/* money power info table */
static const int money_power_tbl[mHsRm_HUUSUI_NUM][2] = {
{ mHsRm_WALL_NON, 0 }, /* mHsRm_HUUSUI_NONE */
{ mHsRm_WALL_WST, 4 }, /* mHsRm_HUUSUI_YELLOW */
{ mHsRm_WALL_NON, 0 }, /* mHsRm_HUUSUI_RED */
{ mHsRm_WALL_NTH, 2 }, /* mHsRm_HUUSUI_ORANGE */
{ mHsRm_WALL_STH, 2 }, /* mHsRm_HUUSUI_GREEN */
{ mHsRm_WALL_ALL, 4 } /* mHsRm_HUUSUI_LUCKY */
};
/* goods power info table */
static const int goods_power_tbl[mHsRm_HUUSUI_NUM][2] = {
{ mHsRm_WALL_NON, 0 }, /* mHsRm_HUUSUI_NONE */
{ mHsRm_WALL_NON, 0 }, /* mHsRm_HUUSUI_YELLOW */
{ mHsRm_WALL_EST, 8 }, /* mHsRm_HUUSUI_RED */
{ mHsRm_WALL_NTH, 4 }, /* mHsRm_HUUSUI_ORANGE */
{ mHsRm_WALL_STH, 4 }, /* mHsRm_HUUSUI_GREEN */
{ mHsRm_WALL_ALL, 8 } /* mHsRm_HUUSUI_LUCKY */
};
/**
* @brief Feng Shui scoring algorithm for a single furniture.
*
* This function checks which side of the room the furniture is on,
* along with its orientation. It returns the point score for both
* money power and goods power into 'money_power' and 'goods_power'.
* The result can be negative if a 'doll'/'item with a face' is facing
* the wall.
*
* @param ftr The actor furniture number
* @param ut_x Unit x position
* @param ut_z Unit z position
* @param money_power Calculated money power for the furniture position
* @param goods_power Calculated goods power for the furniture position
**/
static void mHsRm_EvaluateHuusuiPoint_Single(mActor_name_t ftr, int ut_x, int ut_z, int ut_max, int* money_power, int* goods_power) {
int i;
int ftr_idx;
int room_side_bits;
int ut_value;
int rotation_bits;
int huusui_type;
int room_side_tbl[mHsRm_DIRECTION_NUM];
int rotation_tbl[mHsRm_DIRECTION_NUM];
mRmTp_FtrPlaceInfo_t place_info;
int ftr_rot;
int has_face;
int start_ut;
*money_power = 0;
*goods_power = 0;
ftr_idx = mRmTp_FtrItemNo2FtrIdx(ftr);
ftr_rot = FTR_GET_ROTATION(ftr);
huusui_type = mMkRm_ftr_info[ftr_idx].huusui_type;
has_face = mMkRm_ftr_info[ftr_idx].has_face;
ut_value = mHsRm_unit_value[mRmTp_GetFurnitureData(ftr, ut_x, ut_z, &place_info)]; /* number of units occupied by this furniture */
/* maximum top/left position for feng shui */
if (ut_max == mHsRm_UNIT_MAX_S && ut_value == 1) {
start_ut = 1;
}
else {
start_ut = 2;
}
for (i = 0; i < mHsRm_DIRECTION_NUM; i++) {
room_side_tbl[i] = 0;
rotation_tbl[i] = 0;
}
/* loop through all units occupied by the furniture and check feng shui parameters on each unit */
for (i = 0; i < ut_value; i++) {
if (place_info.units[i].ut_z <= start_ut) {
room_side_tbl[mHsRm_DIRECTION_NORTH]++;
if (place_info.units[i].ut_z <= 1) {
rotation_tbl[mHsRm_DIRECTION_NORTH]++;
}
}
else if (place_info.units[i].ut_z >= ((ut_max - start_ut) - 1)) {
room_side_tbl[mHsRm_DIRECTION_SOUTH]++;
if (place_info.units[i].ut_z >= ut_max - 2) {
rotation_tbl[mHsRm_DIRECTION_SOUTH]++;
}
}
if (place_info.units[i].ut_x <= start_ut) {
room_side_tbl[mHsRm_DIRECTION_WEST]++;
if (place_info.units[i].ut_x <= 1) {
rotation_tbl[mHsRm_DIRECTION_WEST]++;
}
}
else if (place_info.units[i].ut_x >= ((ut_max - start_ut) - 1)) {
room_side_tbl[mHsRm_DIRECTION_EAST]++;
if (place_info.units[i].ut_x >= ut_max - 2) {
rotation_tbl[mHsRm_DIRECTION_EAST]++;
}
}
}
room_side_bits = 0;
rotation_bits = 0;
/* log positioning & rotation */
for (i = 0; i < mHsRm_DIRECTION_NUM; i++) {
/* if all units belonging to this furniture are in the same feng shui room side, add feng shui type */
if (ut_value == room_side_tbl[i]) {
room_side_bits |= (1 << i);
}
/* if any of the furnitures units are directly adjecent to a wall, mark it for rotation check */
if ((ut_value >= 2 && rotation_tbl[i] >= 2) || (ut_value == 1 && rotation_tbl[i] >= 1)) {
rotation_bits |= (1 << i);
}
}
if (huusui_type == mHsRm_HUUSUI_LUCKY) {
*money_power += mHsRm_MONEY_LUCKY_PTS;
*goods_power += mHsRm_GOODS_LUCKY_PTS;
}
if (room_side_bits != 0) {
for (i = 0; i < mHsRm_DIRECTION_NUM; i++) {
if (huusui_type != mHsRm_HUUSUI_LUCKY) {
/* if the furniture was properly placed entirely in the feng shui area, check points & add */
if (room_side_bits & (1 << i)) {
if (money_power_tbl[huusui_type][0] & (1 << i)) {
*money_power += money_power_tbl[huusui_type][1];
}
if (goods_power_tbl[huusui_type][0] & (1 << i)) {
*goods_power += goods_power_tbl[huusui_type][1];
}
}
}
}
/* If the furniture has a "face" (front side), deduct points if that side is facing the wall */
if (has_face != 0) {
for (i = 0; i < mHsRm_DIRECTION_NUM; i++) {
/* check is for furniture is directly adjacent to the given wall and the rotation is the same direction as the wall */
if ((rotation_bits & (1 << i)) && (ftr_rot == i)) {
*money_power -= mHsRm_MONEY_BAD_PTS;
*goods_power -= mHsRm_GOODS_BAD_PTS;
}
}
}
}
}
/**
* @brief Scores an entire room's Feng Shui.
*
* @param layers Pointer to array of mHm_lyr_c room layers to score (main & secondary)
* @param ut_max The maximum unit position (both x & z) for the room's size
* @param money_power Calculated room money power
* @param goods_power Calculated room goods power
**/
static void mHsRm_EvaluateHuusuiPoint(mHm_lyr_c** layers, int ut_max, int* money_power, int* goods_power) {
int room_money_power;
int room_goods_power;
int lyr;
int ut_x;
int ut_z;
room_money_power = 0;
room_goods_power = 0;
/* loop through each unit on both main & secondary layers and score each ftr */
for (lyr = 0; lyr < 2; lyr++) {
mHm_lyr_c* layer = layers[lyr];
for (ut_z = 0; ut_z < ut_max; ut_z++) {
for (ut_x = 0; ut_x < ut_max; ut_x++) {
mActor_name_t item_no = layer->items[ut_z][ut_x];
if (ITEM_IS_FTR(item_no)) {
int item_money_power;
int item_goods_power;
mHsRm_EvaluateHuusuiPoint_Single(item_no, ut_x, ut_z, ut_max, &item_money_power, &item_goods_power);
room_money_power += item_money_power;
room_goods_power += item_goods_power;
}
}
}
}
*money_power += room_money_power;
*goods_power += room_goods_power;
}
/**
* @brief Main Feng Shui scoring function. Will score all three rooms in house
* depending on house size.
*
* @param player_no The index of the player whose house will be scored for Feng Shui
**/
extern void mHsRm_HuusuiRoomOvl(int player_no) {
int ut_max;
mHm_hs_c* home;
int money_power;
int goods_power;
mHm_lyr_c* layers[2];
f32 real_goods_power;
home = Save_Get(homes + mHS_get_arrange_idx(player_no));
money_power = 0;
goods_power = 0;
/* Evaluate the main room first */
ut_max = mHsRm_unit_max[home->size_info.size];
layers[0] = &home->floors[mHm_ROOM_MAIN].layer_main;
layers[1] = &home->floors[mHm_ROOM_MAIN].layer_secondary;
mHsRm_EvaluateHuusuiPoint(layers, ut_max, &money_power, &goods_power);
/* Evaluate the second floor next if it exists */
if (home->size_info.size == mHm_HOMESIZE_UPPER) {
layers[0] = &home->floors[mHm_ROOM_UPPER].layer_main;
layers[1] = &home->floors[mHm_ROOM_UPPER].layer_secondary;
mHsRm_EvaluateHuusuiPoint(layers, mHsRm_UNIT_MAX_UPPER, &money_power, &goods_power);
}
/* Finally, evaluate the basement if it exists */
if (home->flags.has_basement == TRUE) {
layers[0] = &home->floors[mHm_ROOM_BASEMENT].layer_main;
layers[1] = &home->floors[mHm_ROOM_BASEMENT].layer_secondary;
mHsRm_EvaluateHuusuiPoint(layers, mHsRm_UNIT_MAX_BASEMENT, &money_power, &goods_power);
}
/* Goods power is clamed to its upper bound of 40 */
if (goods_power > mHsRm_GOODS_POWER_MAX) {
goods_power = mHsRm_GOODS_POWER_MAX;
}
/* Adjust goods power by dividing it in half and rounding up */
real_goods_power = (f32)goods_power * 0.5f;
goods_power = real_goods_power;
/* Always round up if there's any fractional part to goods_power */
real_goods_power -= goods_power;
if (real_goods_power > 0.0f) {
goods_power++;
}
Common_Set(money_power, money_power);
Common_Set(goods_power, goods_power);
}
File diff suppressed because it is too large Load Diff
+3 -4
View File
@@ -1,13 +1,12 @@
#include "m_room_type.h"
#include "m_name_table.h"
#define FTR_NO_2_FTR_IDX(f) ((f) >> 2)
#define NUM_FTR_IN_TYPE (FTR_NO_2_FTR_IDX(0x1000))
#define IS_FTR(f) ((f) == FG_FTR0_TYPE || (f) == FG_FTR1_TYPE)
extern int mRmTp_FtrItemNo2FtrIdx(u16 ftr_no) {
int type = GET_FG_TYPE(ftr_no);
if (IS_FTR(type)) {
if (type == FG_FTR0_TYPE) {
if (ITEM_IS_FTR(ftr_no)) {
if (ITEM_NAME_GET_TYPE(ftr_no) == NAME_TYPE_FTR0) {
return FTR_NO_2_FTR_IDX(ftr_no - FTR0_NO_START);
}
return FTR_NO_2_FTR_IDX(ftr_no - FTR1_NO_START) + NUM_FTR_IN_TYPE;