From 8f21921cbb98172a07eb91a13313421e729d9347 Mon Sep 17 00:00:00 2001 From: Cuyler36 Date: Mon, 24 Apr 2023 21:22:58 -0400 Subject: [PATCH] Implement & link m_kabu_manager.c --- config/rel_slices.yml | 4 + include/m_kabu_manager.h | 10 +- rel/m_kabu_manager.c | 245 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 257 insertions(+), 2 deletions(-) create mode 100644 rel/m_kabu_manager.c diff --git a/config/rel_slices.yml b/config/rel_slices.yml index 93c6421f..d3aa6a10 100644 --- a/config/rel_slices.yml +++ b/config/rel_slices.yml @@ -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] diff --git a/include/m_kabu_manager.h b/include/m_kabu_manager.h index 534c28f3..1516d462 100644 --- a/include/m_kabu_manager.h +++ b/include/m_kabu_manager.h @@ -9,9 +9,13 @@ extern "C" { #endif enum { - Kabu_TRADE_MARKET_TYPE_A, /* spike trend */ + 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_C, /* falling trend */ + + Kabu_TRADE_MARKET_TYPE_NUM }; /* sizeof(Kabu_price_c) == 0x18 */ @@ -21,6 +25,8 @@ typedef struct kabu_price_s { /* 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 diff --git a/rel/m_kabu_manager.c b/rel/m_kabu_manager.c new file mode 100644 index 00000000..d1e0a917 --- /dev/null +++ b/rel/m_kabu_manager.c @@ -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 */ + } + } +}