feat: implement usage-based billing for locomotion

- Enforced the "Velocity Tax": Users moving above walking speed will now incur a per-frame micro-charge.
- Monetized the 'A' button: Initiating verticality now triggers an immediate transaction fee.
- Established "Walking" as the only features available in the Ad-Supported Free Tier.
- Optimized the drain rate to ensure players cannot complete "Bob-omb Battlefield" without at least one refinancing event.
This commit is contained in:
Panic
2025-11-23 15:14:56 -07:00
parent a452ea648c
commit 72052a52af
4 changed files with 57 additions and 1 deletions

View File

@@ -445,6 +445,7 @@ struct MarioState {
/*0xC4*/ f32 windGravity;
// Credit System
/*0xC8*/ s32 numCredits;
/*0xCC*/ s16 framesSinceCreditDeduction;
// -- HackerSM64 MarioState fields begin --
#ifdef BREATH_METER
s16 breath;

View File

@@ -1,5 +1,6 @@
#include <PR/ultratypes.h>
#include "game/mictrotransactions.h"
#include "sm64.h"
#include "area.h"
#include "audio/external.h"
@@ -1218,7 +1219,11 @@ void debug_print_speed_action_normal(struct MarioState *m) {
* Update the button inputs for Mario.
*/
void update_mario_button_inputs(struct MarioState *m) {
if (m->controller->buttonPressed & A_BUTTON) m->input |= INPUT_A_PRESSED;
if (m->controller->buttonPressed & A_BUTTON) {
if (can_afford(m, CREDITS_PER_A_PRESS)) {
m->input |= INPUT_A_PRESSED;
}
}
if (m->controller->buttonDown & A_BUTTON) m->input |= INPUT_A_DOWN;
// Don't update for these buttons if squished.
@@ -1704,6 +1709,11 @@ void queue_rumble_particles(struct MarioState *m) {
*/
s32 execute_mario_action(UNUSED struct Object *obj) {
s32 inLoop = TRUE;
// Add microtransactions here
// No negative credits
if (gMarioState->numCredits < 0) {
gMarioState->numCredits = 0;
}
// Updates once per frame:
vec3f_get_dist_and_angle(gMarioState->prevPos, gMarioState->pos, &gMarioState->moveSpeed, &gMarioState->movePitch, &gMarioState->moveYaw);
@@ -1739,6 +1749,16 @@ s32 execute_mario_action(UNUSED struct Object *obj) {
gMarioState->marioObj->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE;
mario_reset_bodystate(gMarioState);
update_mario_inputs(gMarioState);
update_credit_deduction(gMarioState);
// Deduct credits if moving at speed
if ((gMarioState->framesSinceCreditDeduction >= FRAMES_AT_SPEED) && gMarioState->forwardVel > WALK_SPEED) {
deduct_credits(gMarioState, 1);
}
// If no credits, only walk
if (gMarioState->forwardVel > WALK_SPEED && gMarioState->numCredits <= 0) {
gMarioState->forwardVel = WALK_SPEED;
}
#ifdef PUPPYCAM
if (!(gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_FREE)) {

View File

@@ -0,0 +1,19 @@
#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++;
}

View File

@@ -0,0 +1,16 @@
#ifndef MICROTRANSACTIONS_H
#define MICROTRANSACTIONS_H
#include <PR/ultratypes.h>
#include "macros.h"
#include "types.h"
#define CREDITS_PER_A_PRESS 5
#define FRAMES_AT_SPEED 30
#define WALK_SPEED 8.0f
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);
#endif // MICROTRANSACTIONS_H