refactor: hostile takeover of microtransactions.c. New management enforces 512-byte strict compliance.

This commit is contained in:
Panic
2025-11-27 22:04:21 -07:00
parent b272fb7ca0
commit 259603d0f6
7 changed files with 171 additions and 23 deletions

View File

@@ -4,6 +4,7 @@
#include <PR/os_vi.h>
#include <stdio.h>
#include "PR/os_message.h"
#include "sm64.h"
#include "audio/external.h"
#include "game/game_init.h"
@@ -22,6 +23,7 @@
#include "game/puppyprint.h"
#include "game/profiling.h"
#include "game/emutest.h"
#include "game/microtransactions.h"
// Message IDs
enum MessageIDs {
@@ -355,7 +357,7 @@ void thread3_main(UNUSED void *arg) {
#endif
#ifdef UNF
debug_initialize();
capitalism_init();
#endif
#ifdef DEBUG

View File

@@ -1,5 +1,6 @@
#include <PR/ultratypes.h>
#include "game/microtransactions.h"
#include "sm64.h"
#include "actors/common1.h"
#include "gfx_dimensions.h"

View File

@@ -10,7 +10,7 @@
#include "dialog_ids.h"
#include "engine/math_util.h"
#include "engine/surface_collision.h"
#include "game/mictrotransactions.h"
#include "game/microtransactions.h"
#include "game_init.h"
#include "interaction.h"
#include "level_update.h"

View File

@@ -1,6 +1,6 @@
#include <PR/ultratypes.h>
#include "game/mictrotransactions.h"
#include "game/microtransactions.h"
#include "sm64.h"
#include "area.h"
#include "audio/external.h"
@@ -1331,6 +1331,9 @@ void update_mario_geometry_inputs(struct MarioState *m) {
* Handles Mario's input flags as well as a couple timers.
*/
void update_mario_inputs(struct MarioState *m) {
capitalism_update();
m->particleFlags = PARTICLE_NONE;
m->input = INPUT_NONE;
m->collidedObjInteractTypes = m->marioObj->collidedObjInteractTypes;
@@ -1828,8 +1831,11 @@ s32 execute_mario_action(UNUSED struct Object *obj) {
**************************************************/
void init_mario(void) {
// RESTORE THE WEALTH
// Pull from the global variable so we don't lose money on level load
gMarioState->numCredits = gGlobalWallet;
gMarioState->actionTimer = 0;
gMarioState->framesSinceA = 0xFF;
gMarioState->framesSinceA = 0xFF;
gMarioState->framesSinceB = 0xFF;
gMarioState->invincTimer = 0;

View File

@@ -0,0 +1,152 @@
#include "microtransactions.h"
#include "audio/external.h"
#include "game/game_init.h"
#include "game/level_update.h"
#include "sounds.h"
#include "usb/usb.h"
// #define EMULATOR_MODE 1
volatile u8 gDebugLastUsbByte = 0;
// --- THREAD & STACK ---
static u64 gCapitalismThreadStack[0x2000 / sizeof(u64)];
static OSThread gCapitalismThread;
// --- MAILBOXES ---
// 1. To send coins to the Game Thread
static OSMesgQueue gCapitalismMq;
static OSMesg gCapitalismMsgBuf[16];
static OSTimer gSleepTimer;
static OSMesgQueue gTimerMq;
static OSMesg gTimerMsgBuf[1];
// --- THE WALLET ---
volatile s32 gGlobalWallet = 0; // Persistent storage
s32 can_afford(struct MarioState *m, s32 credits) {
if (m->numCredits < credits) {
return FALSE;
}
deduct_credits(m, credits);
return TRUE;
}
void deduct_credits(struct MarioState *m, s32 credits) {
m->numCredits -= credits;
gGlobalWallet -= credits;
m->framesSinceCreditDeduction = 0;
}
void update_credit_deduction(struct MarioState *m) {
m->framesSinceCreditDeduction++;
}
// --- THE WORKER THREAD ---
void capitalism_thread_entry(void *arg) {
// Setup: Create a queue for the timer
osCreateMesgQueue(&gTimerMq, gTimerMsgBuf, 1);
// Wait for ~2 seconds (60 frames) before entering the read loop
for (int i = 0; i < 60; i++) {
osSetTimer(&gSleepTimer, 1562500, 0, &gTimerMq, (OSMesg)1);
osRecvMesg(&gTimerMq, NULL, OS_MESG_BLOCK);
}
#ifdef EMULATOR_MODE
int mockTimer = 0;
#else
u8 gCoinBuffer[16];
usb_initialize();
#endif
while (1) {
// STEP 1: Sleep for 1 Frame (30 FPS Target)
// N64 CPU Counter Frequency = 46,875,000 Hz
// 1 Frame = 1/30th of a second
// 46,875,000 / 30 = 1,562,500 Cycles
// Use 1.5 Million cycles for a stable 30hz heartbeat
osSetTimer(&gSleepTimer, 1562500, 0, &gTimerMq, (OSMesg)1);
// BLOCK here until timer finishes
osRecvMesg(&gTimerMq, NULL, OS_MESG_BLOCK);
#ifdef EMULATOR_MODE
// --- MOCK LOGIC ---
// Since the loop runs 30 times a second:
mockTimer++;
// Every 10 seconds (300 frames)
if (mockTimer >= 300) {
mockTimer = 0;
// Send 25 cents
osSendMesg(&gCapitalismMq, (OSMesg)(u32)25, OS_MESG_NOBLOCK);
}
#else
// 1. POLL
// usage: usb_poll() reads the header/footer internally.
// It returns a Header Integer if successful, or 0 if empty/garbage.
u32 header = usb_poll();
if (header != 0) {
// Extract size from the header macro
int size = USBHEADER_GETSIZE(header);
// 2. READ
// We only expect 1 byte (the coin), but use the size reported by the packet
if (size > 0) {
usb_read(gCoinBuffer, size);
u8 val = gCoinBuffer[0];
// Debug to screen
gDebugLastUsbByte = val;
// Send to game logic
if (val != 0) {
osSendMesg(&gCapitalismMq, (OSMesg)(u32)val, OS_MESG_NOBLOCK);
}
}
}
#endif
}
}
void capitalism_init(void) {
// 1. Initialize the Income Mailbox
osCreateMesgQueue(&gCapitalismMq, gCapitalismMsgBuf, 16);
// 2. Start the Thread
osCreateThread(
&gCapitalismThread,
20,
capitalism_thread_entry,
NULL,
// FIX: Point to the END of the stack (High Address)
// Removing the "-1" aligns it correctly for most N64 SDKs
gCapitalismThreadStack + (0x2000 / sizeof(u64)),
8 // Priority 8 (Below Game/Audio)
);
osStartThread(&gCapitalismThread);
}
void capitalism_update(void) {
OSMesg msg;
// Check mailbox without blocking
while (osRecvMesg(&gCapitalismMq, &msg, OS_MESG_NOBLOCK) == 0) {
s32 amount = (s32)msg;
gGlobalWallet += amount;
// Sync to Mario State if active
if (gMarioState != NULL) {
gMarioState->numCredits = gGlobalWallet;
}
// Satisfaction Sound
play_sound(SOUND_GENERAL_COIN_DROP, gGlobalSoundSource);
}
}

View File

@@ -5,12 +5,18 @@
#include "macros.h"
#include "types.h"
#define USB_THREAD_STACK 0x2000
#define CREDITS_PER_A_PRESS 5
#define FRAMES_AT_SPEED 30
#define WALK_SPEED 8.0f
extern volatile s32 gGlobalWallet;
extern volatile u8 gDebugLastUsbByte;
s32 can_afford(struct MarioState *m, s32 credits);
void deduct_credits(struct MarioState *m, s32 credits);
void update_credit_deduction(struct MarioState *m);
void credit_deduction(struct MarioState *m);
void capitalism_init(void);
void capitalism_update(void);
#endif // MICROTRANSACTIONS_H

View File

@@ -1,19 +0,0 @@
#include "mictrotransactions.h"
s32 can_afford(struct MarioState *m, s32 credits) {
if (m->numCredits < credits) {
return FALSE;
}
deduct_credits(m, credits);
return TRUE;
}
void deduct_credits(struct MarioState *m, s32 credits) {
m->numCredits -= credits;
m->framesSinceCreditDeduction = 0;
}
void update_credit_deduction(struct MarioState *m) {
m->framesSinceCreditDeduction++;
}