Merge pull request #22 from Cuyler36/more_save_headers

Implement more save structs & m_kabu_manager.c
This commit is contained in:
Prakxo
2023-04-25 08:15:10 +02:00
committed by GitHub
10 changed files with 475 additions and 3 deletions
+4
View File
@@ -4,6 +4,10 @@ m_debug_hayakawa.c:
.text: [0x803965E4, 0x803973E8]
.rodata: [0x80641D50, 0x80641D90]
.data: [0x80651328, 0x80651358]
m_kabu_manager.c:
.text: [0x803B5CC4, 0x803B6280]
.rodata: [0x80642480, 0x806424C0]
.data: [0x80655D48, 0x80655D78]
m_malloc.c:
.text: [0x803BC510, 0x803BC70C]
.bss: [0x81297CA0, 0x81297CD0]
+22 -3
View File
@@ -10,6 +10,13 @@
#include "m_private.h"
#include "m_npc.h"
#include "m_field_make.h"
#include "m_notice.h"
#include "m_shop.h"
#include "m_kabu_manager.h"
#include "m_post_office.h"
#include "m_police_box.h"
#include "m_snowman.h"
#include "m_config.h"
#ifdef __cplusplus
extern "C" {
@@ -40,15 +47,27 @@ typedef struct Save_s {
/* 0x000019 */ u8 remove_animal_idx; /* index of the villager which is scheduled to leave town, 0xFF when none selected */
/* 0x00001A */ u16 copy_protect; /* 'unique' value between [1, 65520] used for copy protection (see mCD_get_land_copyProtect) */
/* 0x00001C */ u8 pad_1C[4];
/* 0x000020 */ Private_c private[PLAYER_NUM];
/* 0x000020 */ Private_c private[PLAYER_NUM]; /* player data */
/* 0x009120 */ mLd_land_info_c land_info; /* town name & id */
/* 0x00912C */ u8 _tmp1[0xBBC]; /* notice board info goes here */
/* 0x00912C */ mNtc_board_post_c noticeboard[mNtc_BOARD_POST_COUNT]; /* noticeboard posts */
/* 0x009CE4 */ u8 pad_9CE4[4];
/* 0x009CE8 */ mHm_hs_c homes[PLAYER_NUM]; /* player house data */
/* 0x0137A8 */ mFM_fg_c fg[FG_BLOCK_Z_NUM][FG_BLOCK_X_NUM]; /* fg items (fg = foreground?) */
/* 0x0173A8 */ mFM_combination_c combi_table[BLOCK_Z_NUM][BLOCK_X_NUM]; /* acre 'combination' data */
/* 0x017438 */ Animal_c animals[ANIMAL_NUM_MAX]; /* villagers in town */
/* 0x020330 */ AnmPersonalID_c last_removed_animal_id; /* ID of last villager who left town */
/* 0x02033E */ u8 _tmp3[0xBD6];
/* 0x020340 */ Shop_c shop; /* Nook's shop */
/* 0x020480 */ Kabu_price_c kabu_price_schedule; /* Stalk Market info */
/* 0x020498 */ u8 _tmp3[0x1F0]; /* saved events go here, but have a lot of structs in a union so holding off */
/* 0x020688 */ mActor_name_t fruit; /* town fruit type */
/* 0x02068A */ u8 house_arrangement; /* 2 bits for each player for the # of house they own */
/* 0x02068B */ u8 num_statues; /* number of statues built for players who have paid off their debts */
/* 0x02068C */ lbRTC_time_c all_grow_renew_time; /* renewal time for fg items handled by mAgrw_RenewalFgItem_ovl */
/* 0x020694 */ PostOffice_c post_office; /* post office data */
/* 0x020ED0 */ PoliceBox_c police_box; /* police station lost & found */
/* 0x020EF8 */ mSN_snowman_save_c snowmen; /* saved snowmen data */
/* 0x020F08 */ u64 melody; /* town tune, each nibble is a note (16 notes) */
/* 0x020F10 */ Config_c config; /* saved config for sound mode, voice mode, and vibration */
/* 0x020F14 */ lbRTC_ymd_t renew_time; /* next renew date */
/* 0x020F18 */ u8 station_type; /* train station type */
/* 0x020F19 */ u8 weather; /* upper nibble is intensity, lower nibble is type */
+22
View File
@@ -0,0 +1,22 @@
#ifndef M_CONFIG_H
#define M_CONFIG_H
#include "types.h"
#ifdef __cplusplus
extern "C" {
#endif
/* sizeof(Config_c) == 4 */
typedef struct config_s {
/* 0x00 */ u8 sound_mode; /* mono, stereo, ... */
/* 0x01 */ u8 voice_mode; /* silent, babblese, animalese */
/* 0x02 */ u8 vibration_enabled; /* true/false */
/* 0x03 */ u8 unused; /* might not exist */
} Config_c;
#ifdef __cplusplus
}
#endif
#endif
+20
View File
@@ -2,11 +2,31 @@
#define M_KABU_MANAGER_H
#include "types.h"
#include "lb_rtc.h"
#ifdef __cplusplus
extern "C" {
#endif
enum {
Kabu_TRADE_MARKET_TYPE_START,
Kabu_TRADE_MARKET_TYPE_A = Kabu_TRADE_MARKET_TYPE_START, /* spike trend */
Kabu_TRADE_MARKET_TYPE_B, /* random trend */
Kabu_TRADE_MARKET_TYPE_C, /* falling trend */
Kabu_TRADE_MARKET_TYPE_NUM
};
/* sizeof(Kabu_price_c) == 0x18 */
typedef struct kabu_price_s {
/* 0x00 */ u16 daily_price[lbRTC_WEEKDAYS_MAX];
/* 0x0E */ u16 trade_market;
/* 0x10 */ lbRTC_time_c update_time;
} Kabu_price_c;
extern void Kabu_decide_price_schedule();
extern u16 Kabu_get_price();
extern void Kabu_manager();
#ifdef __cplusplus
+24
View File
@@ -0,0 +1,24 @@
#ifndef M_NOTICE_H
#define M_NOTICE_H
#include "types.h"
#include "m_mail.h"
#include "lb_rtc.h"
#ifdef __cplusplus
extern "C" {
#endif
#define mNtc_BOARD_POST_COUNT 15
/* sizeof(mNtc_board_post) == 0xC8 */
typedef struct notice_board_post_s {
/* 0x00 */ u8 message[MAIL_BODY_LEN]; /* post contents */
/* 0xC0 */ lbRTC_time_c post_time; /* date-time of post */
} mNtc_board_post_c;
#ifdef __cplusplus
}
#endif
#endif
+22
View File
@@ -0,0 +1,22 @@
#ifndef M_POLICE_BOX_H
#define M_POLICE_BOX_H
#include "types.h"
#include "m_actor_type.h"
#ifdef __cplusplus
extern "C" {
#endif
#define mPB_POLICE_BOX_ITEM_STORAGE_COUNT 20
/* sizeof(PoliceBox_c) == 0x28 */
typedef struct police_box_s {
/* 0x00 */ mActor_name_t keep_items[mPB_POLICE_BOX_ITEM_STORAGE_COUNT];
} PoliceBox_c;
#ifdef __cplusplus
}
#endif
#endif
+40
View File
@@ -0,0 +1,40 @@
#ifndef M_POST_OFFICE_H
#define M_POST_OFFICE_H
#include "types.h"
#include "m_mail.h"
#include "lb_rtc.h"
#ifdef __cplusplus
extern "C" {
#endif
#define mPO_MAIL_STORAGE_SIZE 5
/* sizeof(PostOffice_c) == 0x83C */
typedef struct post_office_s {
/* 0x000 */ s16 keep_mail_sum_players; /* sum of stored mail from players, see mPO_get_keep_mail_sum */
/* 0x002 */ s16 keep_mail_sum_npcs; /* sum of stored mail from NPCs, see mPO_get_keep_mail_sum */
/* 0x004 */ s16 mail_recipient_flags; /* flags to keep track of which players will receive mail */
/* 0x006 */ u16 unused_6; /* definitely here, as Mail_c has 2 byte alignment */
/* 0x008 */ Mail_c mail[mPO_MAIL_STORAGE_SIZE];
/* 0x5DA */ Mail_c leaflet;
/* 0x704 */ Mail_c event_leaflet;
/* certainly a union based on code usage */
/* 0x830 */ union {
/* 0x830 */ int raw; /* used in mPO_post_office_init */
struct {
/* 0x830 */ s16 leaflet_flags; /* bitfield of players who will receive the current 'leaflet' */
/* 0x832 */ s16 event_flags; /* bitfield of players who will receive the current 'event leaflet' */
};
} leaflet_recipient_flags; /* similar to mail_recipient_flags, just for 'leaflets' */
/* 0x834 */ lbRTC_time_c delivery_time; /* time when Pete should 'deliver' the mail */
} PostOffice_c;
#ifdef __cplusplus
}
#endif
#endif
+47
View File
@@ -3,11 +3,58 @@
#include "types.h"
#include "libu64/gfxprint.h"
#include "lb_rtc.h"
#include "m_personal_id.h"
#include "m_actor_type.h"
#ifdef __cplusplus
extern "C" {
#endif
#define mSP_PERSONAL_ID_COUNT 10
#define mSP_GOODS_COUNT 39
#define mSP_LOTTERY_ITEM_COUNT 3
enum {
mSP_LIST_FURNITURE,
mSP_LIST_PAPER,
mSP_LIST_CLOTH,
mSP_LIST_CARPET,
mSP_LIST_WALLPAPER,
mSP_LIST_MAX
};
/* sizeof(mSP_goods_priority_list_c) == 1 */
typedef struct shop_goods_priority_list_s {
u8 a:2; /* list A rarity */
u8 b:2; /* list B rarity */
u8 c:2; /* list C rarity */
u8 pad:2;
} mSP_goods_priority_list_c;
/* sizeof(Shop_c) == 0x140 */
typedef struct shop_s {
/* 0x000 */ mSP_goods_priority_list_c priority_lists[mSP_LIST_MAX]; /* ABC list rarity (known internally as priority) */
/* 0x006 */ PersonalID_c unused_ids[mSP_PERSONAL_ID_COUNT]; /* unused personal ids */
/* 0x0CE */ mActor_name_t items[mSP_GOODS_COUNT]; /* standard shop items */
/* 0x11C */ mActor_name_t rare_item; /* spotlight rare item taken from rare furniture ABC list */
/* 0x11E */ mActor_name_t lottery_items[mSP_LOTTERY_ITEM_COUNT]; /* lottery items */
/* 0x124 */ s8 flowers_candy_grab_bag_count; /* count of items that are flowers, candy, or grab bags */
/* 0x126 */ struct {
/* 0x126 */ u16 shop_level:2; /* shop type, 0 = Cranny, 1 = Nook 'n Go, 2 = Nookway, 3 = Nookington's */
/* 0x126 */ u16 upgrading_today:1; /* enabled when the shop is 'undergoing renovations' */
/* 0x126 */ u16 send_upgrade_notice:1; /* triggers the upgrade letter to be sent out */
/* 0x126 */ u16 not_loaded_before:1; /* cleared when the shop actor has loaded for the first time in a play session */
/* 0x126/0x127 */ u16 paint_color:4; /* paint bucket color being sold */
/* 0x127 */ u16 unused:7; /* seems to be unused */
} shop_info;
/* 0x128 */ u32 sales_sum; /* current money towards upgrading shop */
/* 0x12C */ lbRTC_time_c exchange_time; /* last time the shop's items were updated */
/* 0x134 */ lbRTC_time_c renewal_time; /* last time the shop was 'renewed' which includes upgrading its 'level' */
/* 0x13C */ int visitor_flag; /* set when a foreign player enters Nook's shop, required for Nookington's */
} Shop_c;
extern void mSP_PrintNowShopSalesSum(gfxprint_t* gfxprint);
extern void mItemDebug_ItemDebugMain();
+29
View File
@@ -0,0 +1,29 @@
#ifndef M_SNOWMAN_H
#define M_SNOWMAN_H
#include "types.h"
#ifdef __cplusplus
extern "C" {
#endif
#define mSN_SAVE_COUNT 3
/* sizeof(mSN_snowman_data_c) == 4 */
typedef struct snowman_data_s {
/* 0x00 */ u8 exists; /* when non-zero, snowman 'exists' */
/* 0x01 */ u8 head_size; /* size of the snowman's head */
/* 0x02 */ u8 body_size; /* size of the snowman's body */
/* 0x03 */ u8 score; /* score based on snowman proportions */
} mSN_snowman_data_c;
/* sizeof(mSN_snowman_save_c) == 0xC */
typedef struct snowman_save_data_s {
/* 0x00 */ mSN_snowman_data_c snowmen_data[mSN_SAVE_COUNT];
} mSN_snowman_save_c;
#ifdef __cplusplus
}
#endif
#endif
+245
View File
@@ -0,0 +1,245 @@
#include "m_kabu_manager.h"
#include "lb_rtc.h"
#include "m_common_data.h"
#include "libc64/qrand.h"
#define TRADE_MARKET_ODDS_NUM (Kabu_TRADE_MARKET_TYPE_NUM - 1)
/**
* @brief Set Stalk Market update time to current day at 00:00.
**/
static void Kabu_set_schedule_day() {
lbRTC_time_c* kabu_update_time = Save_GetPointer(kabu_price_schedule.update_time);
/* copy current date-time */
lbRTC_TimeCopy(kabu_update_time, Common_GetPointer(time.rtc_time));
/* set time to beginning of day */
kabu_update_time->hour = 0;
kabu_update_time->min = 0;
kabu_update_time->sec = 0;
/* back-track to the last Sunday */
lbRTC_Sub_DD(kabu_update_time, kabu_update_time->weekday);
kabu_update_time->weekday = lbRTC_SUNDAY;
}
/**
* @brief Decide a new Stalk Market trend using the last trend for % odds.
**/
static void Kabu_decide_trade_market() {
static f32 next_trade_market_typeA[TRADE_MARKET_ODDS_NUM] = {
0.5f, /* Type A (50%) */
0.3f /* Type B (30%) */
//0.2f /* Type C (20%) */
};
static f32 next_trade_market_typeB[TRADE_MARKET_ODDS_NUM] = {
0.6f, /* Type A (60%) */
0.2f /* Type B (20%) */
//0.1f /* Type C (20%) */
};
static f32 next_trade_market_typeC[TRADE_MARKET_ODDS_NUM] = {
0.6f, /* Type A (60%) */
0.3f /* Type B (30%) */
//0.1f /* Type C (10%) */
};
static f32* next_trade_market[Kabu_TRADE_MARKET_TYPE_NUM] = {
next_trade_market_typeA, next_trade_market_typeB, next_trade_market_typeC
};
f32* next_type_market = next_trade_market[Save_Get(kabu_price_schedule.trade_market)];
f32 chosen = fqrand(); /* [0.0f, 1.0f) */
int i;
/* Subtract odds from chosen until we're below the current odds, or reach the last market type */
for (i = 0; i < TRADE_MARKET_ODDS_NUM; i++) {
if (chosen < *next_type_market) {
break;
}
chosen -= *next_type_market;
next_type_market++;
}
if (i < Kabu_TRADE_MARKET_TYPE_START || i >= Kabu_TRADE_MARKET_TYPE_NUM) {
i = 0;
}
Save_Set(kabu_price_schedule.trade_market, i);
}
/* Predeclare schedule function defs */
static void Kabu_decide_price_schedule_typeA();
static void Kabu_decide_price_schedule_typeB();
static void Kabu_decide_price_schedule_typeC();
#define TRADE_MARKET_A_SPIKE_DAYS 5
#define TRADE_MARKET_A_SPIKE_DAY_BEGIN lbRTC_MONDAY
#define TRADE_MARKET_A_SPIKE_MULTIPLIER 8.0f
/**
* @brief Generate weekly Stalk Market prices in a 'random' trend. With one huge spike.
*
* The spike day will be [Monday, Friday], and will always be 8 times the Sunday buy price.
**/
static void Kabu_decide_price_schedule_typeA() {
f32 spike_price;
int spike_day;
Kabu_decide_price_schedule_typeB(); /* start with a 'random' trend */
/* determine spike price & spike day */
spike_price = Save_Get(kabu_price_schedule.daily_price[lbRTC_SUNDAY]) * TRADE_MARKET_A_SPIKE_MULTIPLIER;
spike_day = fqrand() * TRADE_MARKET_A_SPIKE_DAYS;
spike_day += lbRTC_MONDAY;
Save_Set(kabu_price_schedule.daily_price[spike_day], spike_price);
}
#define TRADE_MARKET_B_SUNDAY_PRICE_MULT 0.8f /* 0.8x (80%) minimum possible price */
#define TRADE_MARKET_B_PRICE_INCREASE_START 1.05f /* 1.05x (105%) initial increase rate */
#define TRADE_MARKET_B_PRICE_DECREASE_RATE 0.7f /* 0.7x (70%) static decrease rate */
#define TRADE_MARKET_B_PRICE_INCREASE_RATE 0.01f /* 1% linear increase percent rate */
#define TRADE_MARKET_B_PRICE_DECREASE_ODDS_START 0.1f /* 10% initial decrease chance */
#define TRADE_MARKET_B_PRICE_DECREASE_ODDS_RATE 0.14f /* 14% decrease percentage increase rate */
#define TRADE_MARKET_B_PRICE_DECREASE_LOWER_RATE 0.3f /* 30% decrease percentage decrease rate */
/**
* @brief Generate weekly Stalk Market prices in a 'random' trend.
**/
static void Kabu_decide_price_schedule_typeB() {
u16* prices = Save_GetPointer(kabu_price_schedule.daily_price[lbRTC_MONDAY]);
f32 current_price_mult = TRADE_MARKET_B_PRICE_INCREASE_START;
f32 price_decrease_percent = TRADE_MARKET_B_PRICE_DECREASE_ODDS_START;
f32 current_price = (f32)Save_Get(kabu_price_schedule.daily_price[lbRTC_SUNDAY]);
f32 min_price = (f32)Save_Get(kabu_price_schedule.daily_price[lbRTC_SUNDAY]) * TRADE_MARKET_B_SUNDAY_PRICE_MULT;
int day;
for (day = lbRTC_MONDAY; day <= lbRTC_SATURDAY; day++) {
/* check if rng roll is less than our decrease chance */
if (fqrand() < price_decrease_percent) {
current_price *= TRADE_MARKET_B_PRICE_DECREASE_RATE; /* decrease price */
if (current_price > min_price) {
/* if decreased price is greater than the minimum decrease price, clamp it */
current_price = min_price;
}
/* lower decrease chance, and clamp it to <= initial decrease odds */
price_decrease_percent *= TRADE_MARKET_B_PRICE_DECREASE_LOWER_RATE;
if (price_decrease_percent > TRADE_MARKET_B_PRICE_DECREASE_ODDS_START) {
price_decrease_percent = TRADE_MARKET_B_PRICE_DECREASE_ODDS_START;
}
}
else {
/* increase increase multiplier & price, but also increase decrease chance */
current_price *= current_price_mult;
current_price_mult += TRADE_MARKET_B_PRICE_INCREASE_RATE;
price_decrease_percent += TRADE_MARKET_B_PRICE_DECREASE_ODDS_RATE;
}
*prices++ = current_price; /* move to next day save slot */
}
}
#define TRADE_MARKET_C_ADJUST_MULT_SPREAD 0.14999998f /* mwcc doesn't generate the same */ //0.15f
#define TRADE_MARKET_C_ADJUST_MULT_BASE 0.8f
/**
* @brief Generate weekly Stalk Market prices in a 'falling' trend.
**/
static void Kabu_decide_price_schedule_typeC() {
u16* price = Save_GetPointer(kabu_price_schedule.daily_price[lbRTC_MONDAY]);
f32 current_price = Save_Get(kabu_price_schedule.daily_price[lbRTC_SUNDAY]);
int day;
for (day = lbRTC_MONDAY; day <= lbRTC_SATURDAY; day++) {
current_price *= (TRADE_MARKET_C_ADJUST_MULT_BASE + TRADE_MARKET_C_ADJUST_MULT_SPREAD * fqrand()); /* [80%, 95%) */
*price++ = current_price;
}
}
#define TRADE_MARKET_SUNDAY_BASE_PRICE 100.0f
/**
* @brief Generate Sunday Stalk Market buy price.
*
* Prices will always been in the range of [70, 129] bells.
**/
static void Kabu_decide_price_sunday() {
f32 price = 1.0f + (fqrand() - 0.5f) * 0.6f;
Save_Set(kabu_price_schedule.daily_price[lbRTC_SUNDAY], price * TRADE_MARKET_SUNDAY_BASE_PRICE); /* [0.7, 1.3) * 100.0f = [70, 130) bells */
}
/**
* @brief Run the set Stalk Market trend algorithm.
**/
static void Kabu_decide_price_without_sunday() {
static void (*process[])(void) = { Kabu_decide_price_schedule_typeA, Kabu_decide_price_schedule_typeB, Kabu_decide_price_schedule_typeC };
(*process[Save_Get(kabu_price_schedule.trade_market)])();
}
/**
* @brief Picks a new Stalk Market trend, generates new sell prices, & sets the update time.
**/
static void Kabu_decide_price_schedule_without_sunday() {
Kabu_decide_trade_market();
Kabu_decide_price_without_sunday();
Kabu_set_schedule_day();
}
/**
* @brief Generates a new Stalk Market Sunday buy price, Stalk Market trend, sell prices, & sets the update time.
**/
extern void Kabu_decide_price_schedule() {
Kabu_decide_price_sunday();
Kabu_decide_price_schedule_without_sunday();
}
/**
* @brief Retrieves the current day's Stalk Market price.
**/
extern u16 Kabu_get_price() {
return Save_Get(kabu_price_schedule.daily_price[Common_Get(time.rtc_time.weekday)]);
}
/**
* @brief Checks if the Stalk Market should be re-rolled based on the current date
*
* It will re-roll the Stalk Market Trend & sell prices if called on Sunday
* after the Stalk Market has already been set for the week.
*
* It will completely re-roll Stalk Market if the date is greater than one week
* from the last Stalk Market update.
**/
extern void Kabu_manager() {
lbRTC_time_c* rtc_time = Common_GetPointer(time.rtc_time);
lbRTC_time_c* kabu_update_time = Save_GetPointer(kabu_price_schedule.update_time);
/* Check if being called on the Sunday where the Stalk Market has already been set */
if (lbRTC_IsEqualDate(
rtc_time->year, rtc_time->month, rtc_time->day,
kabu_update_time->year, kabu_update_time->month, kabu_update_time->day
) == lbRTC_EQUAL
) {
Kabu_decide_price_schedule_without_sunday(); /* reset non-sunday prices & the trend type */
}
else {
lbRTC_time_c week_ahead;
lbRTC_time_c week_behind;
lbRTC_TimeCopy(&week_ahead, kabu_update_time);
lbRTC_Add_DD(&week_ahead, lbRTC_WEEK);
lbRTC_TimeCopy(&week_behind, kabu_update_time);
lbRTC_Sub_DD(&week_behind, lbRTC_WEEK);
if (lbRTC_IsOverTime(&week_ahead, Common_GetPointer(time.rtc_time)) == lbRTC_OVER ||
lbRTC_IsOverTime(&week_behind, Common_GetPointer(time.rtc_time)) == lbRTC_LESS
) {
Kabu_decide_price_schedule(); /* greater than one week has passed, reset entire schedule */
}
}
}