Files
ac-decomp/src/m_kabu_manager.c
T
2023-12-09 13:34:31 +01:00

246 lines
8.6 KiB
C

#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 */
}
}
}