Make cheats much better and add new ones (#305)

* Make cheats much better and add new ones

Improved some, added some.
- Formatted cheats code to fit with the rest of sm64's naming style of things like structs
- Cheats will now always check for gServerSettings.enableCheats instead of its own variable
- Moon Jump: Increased vertical speed, automatically exit bonks
- God Mode: Tiny code improvements
- Super Speed: Exponentially improved, moved to step code and now works as it always should have
- Rapid Fire (New): When on, A will become rapid fire
- Always Triple Jump (New): When on, Mario will triple jump regardless of forwards velocity
- BLJ Anywhere (New): When on, spam A while BLJing to BLJ anywhere

* Add m->playerIndex == 0 checks
This commit is contained in:
Agent X 2023-03-27 18:53:12 -04:00 committed by GitHub
parent b738cf73f9
commit f97cc25732
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 95 additions and 31 deletions

View file

@ -2271,7 +2271,7 @@ void check_death_barrier(struct MarioState *m) {
void check_lava_boost(struct MarioState *m) { void check_lava_boost(struct MarioState *m) {
bool allow = true; bool allow = true;
smlua_call_event_hooks_mario_param_ret_bool(HOOK_ALLOW_HAZARD_SURFACE, m, &allow); smlua_call_event_hooks_mario_param_ret_bool(HOOK_ALLOW_HAZARD_SURFACE, m, &allow);
if (m->action == ACT_BUBBLED || (Cheats.enabled && Cheats.godMode) || (!allow)) { return; } if (m->action == ACT_BUBBLED || (gServerSettings.enableCheats && gCheats.godMode) || (!allow)) { return; }
if (!(m->action & ACT_FLAG_RIDING_SHELL) && m->pos[1] < m->floorHeight + 10.0f) { if (!(m->action & ACT_FLAG_RIDING_SHELL) && m->pos[1] < m->floorHeight + 10.0f) {
if (!(m->flags & MARIO_METAL_CAP)) { if (!(m->flags & MARIO_METAL_CAP)) {
m->hurtCounter += (m->flags & MARIO_CAP_ON_HEAD) ? 12 : 18; m->hurtCounter += (m->flags & MARIO_CAP_ON_HEAD) ? 12 : 18;

View file

@ -1548,9 +1548,21 @@ void update_mario_inputs(struct MarioState *m) {
debug_print_speed_action_normal(m); debug_print_speed_action_normal(m);
if (Cheats.enabled && Cheats.moonJump && m->controller->buttonDown & L_TRIG) { if (gServerSettings.enableCheats && gCheats.moonJump && m->playerIndex == 0 && m->controller->buttonDown & L_TRIG) {
if (m->action == ACT_FORWARD_GROUND_KB ||
m->action == ACT_BACKWARD_GROUND_KB ||
m->action == ACT_SOFT_FORWARD_GROUND_KB ||
m->action == ACT_HARD_BACKWARD_GROUND_KB ||
m->action == ACT_FORWARD_AIR_KB ||
m->action == ACT_BACKWARD_AIR_KB ||
m->action == ACT_HARD_FORWARD_AIR_KB ||
m->action == ACT_HARD_BACKWARD_AIR_KB ||
m->action == ACT_AIR_HIT_WALL) {
set_mario_action(m, ACT_FREEFALL, 0);
}
m->faceAngle[1] = m->intendedYaw - approach_s32((s16)(m->intendedYaw - m->faceAngle[1]), 0, 0x800, 0x800); m->faceAngle[1] = m->intendedYaw - approach_s32((s16)(m->intendedYaw - m->faceAngle[1]), 0, 0x800, 0x800);
m->vel[1] = 30; m->vel[1] = 40;
} }
/* Developer stuff */ /* Developer stuff */
@ -1994,14 +2006,18 @@ s32 execute_mario_action(UNUSED struct Object *o) {
np->fadeOpacity += 2; np->fadeOpacity += 2;
gMarioState->fadeWarpOpacity = np->fadeOpacity << 3; gMarioState->fadeWarpOpacity = np->fadeOpacity << 3;
} }
if (gServerSettings.enableCheats) {
if (gCheats.godMode) {
gMarioState->health = 0x880;
gMarioState->healCounter = 0;
gMarioState->hurtCounter = 0;
} }
if (Cheats.enabled) { if (gCheats.infiniteLives && gMarioState->numLives < 100) {
if (Cheats.godMode) { gMarioState->health = 0x880; } gMarioState->numLives = 100;
}
if (Cheats.infiniteLives && gMarioState->numLives < 100) { gMarioState->numLives = 100; } }
if (Cheats.superSpeed && gMarioState->controller->stickMag > 0.5f) { gMarioState->forwardVel += 100; }
} }
if (gMarioState->action) { if (gMarioState->action) {
@ -2116,6 +2132,10 @@ s32 execute_mario_action(UNUSED struct Object *o) {
#endif #endif
} }
if (gServerSettings.enableCheats && gCheats.bljAnywhere && gMarioState->playerIndex == 0 && gMarioState->action == ACT_LONG_JUMP && gMarioState->forwardVel < -15 && gMarioState->input & INPUT_Z_DOWN && gMarioState->pos[1] - gMarioState->floorHeight < 90) {
gMarioState->vel[1] = -30;
}
play_infinite_stairs_music(); play_infinite_stairs_music();
gMarioState->marioObj->oInteractStatus = 0; gMarioState->marioObj->oInteractStatus = 0;
queue_particle_rumble(); queue_particle_rumble();

View file

@ -55,7 +55,7 @@ void play_knockback_sound(struct MarioState *m) {
s32 lava_boost_on_wall(struct MarioState *m) { s32 lava_boost_on_wall(struct MarioState *m) {
bool allow = true; bool allow = true;
smlua_call_event_hooks_mario_param_ret_bool(HOOK_ALLOW_HAZARD_SURFACE, m, &allow); smlua_call_event_hooks_mario_param_ret_bool(HOOK_ALLOW_HAZARD_SURFACE, m, &allow);
if ((Cheats.enabled && Cheats.godMode) || (!allow)) { return FALSE; } if ((gServerSettings.enableCheats && gCheats.godMode) || (!allow)) { return FALSE; }
m->faceAngle[1] = atan2s(m->wallNormal[2], m->wallNormal[0]); m->faceAngle[1] = atan2s(m->wallNormal[2], m->wallNormal[0]);
if (m->forwardVel < 24.0f) { if (m->forwardVel < 24.0f) {
@ -72,7 +72,7 @@ s32 lava_boost_on_wall(struct MarioState *m) {
} }
s32 check_fall_damage(struct MarioState *m, u32 hardFallAction) { s32 check_fall_damage(struct MarioState *m, u32 hardFallAction) {
if (Cheats.enabled && Cheats.godMode) { return FALSE; } if (gServerSettings.enableCheats && gCheats.godMode && m->playerIndex == 0) { return FALSE; }
f32 fallHeight; f32 fallHeight;
f32 damageHeight; f32 damageHeight;

View file

@ -24,6 +24,7 @@
#include "pc/configfile.h" #include "pc/configfile.h"
#include "pc/network/network.h" #include "pc/network/network.h"
#include "pc/lua/smlua.h" #include "pc/lua/smlua.h"
#include "pc/cheats.h"
#define POLE_NONE 0 #define POLE_NONE 0
#define POLE_TOUCHED_FLOOR 1 #define POLE_TOUCHED_FLOOR 1
@ -331,6 +332,11 @@ s32 perform_hanging_step(struct MarioState *m, Vec3f nextPos) {
smlua_call_event_hooks_mario_param(HOOK_BEFORE_PHYS_STEP, m); smlua_call_event_hooks_mario_param(HOOK_BEFORE_PHYS_STEP, m);
if (gServerSettings.enableCheats && gCheats.superSpeed && m->playerIndex == 0) {
m->vel[0] *= SUPER_SPEED_MULTIPLIER;
m->vel[2] *= SUPER_SPEED_MULTIPLIER;
}
struct WallCollisionData wcd = { 0 }; struct WallCollisionData wcd = { 0 };
resolve_and_return_wall_collisions_data(nextPos, 50.0f, 50.0f, &wcd); resolve_and_return_wall_collisions_data(nextPos, 50.0f, 50.0f, &wcd);
m->wall = (wcd.numWalls > 0) m->wall = (wcd.numWalls > 0)

View file

@ -152,7 +152,7 @@ void slide_bonk(struct MarioState *m, u32 fastAction, u32 slowAction) {
s32 set_triple_jump_action(struct MarioState *m, UNUSED u32 action, UNUSED u32 actionArg) { s32 set_triple_jump_action(struct MarioState *m, UNUSED u32 action, UNUSED u32 actionArg) {
if (m->flags & MARIO_WING_CAP) { if (m->flags & MARIO_WING_CAP) {
return set_mario_action(m, ACT_FLYING_TRIPLE_JUMP, 0); return set_mario_action(m, ACT_FLYING_TRIPLE_JUMP, 0);
} else if (m->forwardVel > 20.0f) { } else if (m->forwardVel > 20.0f || (gServerSettings.enableCheats && gCheats.alwaysTripleJump && m->playerIndex == 0)) {
return set_mario_action(m, ACT_TRIPLE_JUMP, 0); return set_mario_action(m, ACT_TRIPLE_JUMP, 0);
} else { } else {
return set_mario_action(m, ACT_JUMP, 0); return set_mario_action(m, ACT_JUMP, 0);
@ -468,7 +468,7 @@ void update_walking_speed(struct MarioState *m) {
} }
// handles the "Super responsive controls" cheat. The content of the "else" is Mario's original code for turning around. // handles the "Super responsive controls" cheat. The content of the "else" is Mario's original code for turning around.
if (Cheats.enabled && Cheats.responsive) { if (gServerSettings.enableCheats && gCheats.responsiveControls && m->playerIndex == 0) {
m->faceAngle[1] = m->intendedYaw; m->faceAngle[1] = m->intendedYaw;
} else { } else {
m->faceAngle[1] = m->intendedYaw - approach_s32((s16)(m->intendedYaw - m->faceAngle[1]), 0, 0x800, 0x800); m->faceAngle[1] = m->intendedYaw - approach_s32((s16)(m->intendedYaw - m->faceAngle[1]), 0, 0x800, 0x800);

View file

@ -21,6 +21,7 @@
#include "pc/network/network.h" #include "pc/network/network.h"
#include "pc/lua/smlua.h" #include "pc/lua/smlua.h"
#include "pc/lua/smlua_hooks.h" #include "pc/lua/smlua_hooks.h"
#include "pc/cheats.h"
#define MIN_SWIM_STRENGTH 160 #define MIN_SWIM_STRENGTH 160
#define MIN_SWIM_SPEED 16.0f #define MIN_SWIM_SPEED 16.0f
@ -186,6 +187,11 @@ u32 perform_water_step(struct MarioState *m) {
smlua_call_event_hooks_mario_param(HOOK_BEFORE_PHYS_STEP, m); smlua_call_event_hooks_mario_param(HOOK_BEFORE_PHYS_STEP, m);
if (gServerSettings.enableCheats && gCheats.superSpeed && m->playerIndex == 0) {
m->vel[0] *= SUPER_SPEED_MULTIPLIER;
m->vel[2] *= SUPER_SPEED_MULTIPLIER;
}
vec3f_copy(step, m->vel); vec3f_copy(step, m->vel);
if (m->action & ACT_FLAG_SWIMMING) { if (m->action & ACT_FLAG_SWIMMING) {

View file

@ -111,7 +111,7 @@ void mario_bonk_reflection(struct MarioState *m, u32 negateSpeed) {
u32 mario_update_quicksand(struct MarioState *m, f32 sinkingSpeed) { u32 mario_update_quicksand(struct MarioState *m, f32 sinkingSpeed) {
bool allow = true; bool allow = true;
smlua_call_event_hooks_mario_param_ret_bool(HOOK_ALLOW_HAZARD_SURFACE, m, &allow); smlua_call_event_hooks_mario_param_ret_bool(HOOK_ALLOW_HAZARD_SURFACE, m, &allow);
if (m->action & ACT_FLAG_RIDING_SHELL || (Cheats.enabled && Cheats.godMode) || (!allow)) { if (m->action & ACT_FLAG_RIDING_SHELL || (gServerSettings.enableCheats && gCheats.godMode && m->playerIndex == 0) || (!allow)) {
m->quicksandDepth = 0.0f; m->quicksandDepth = 0.0f;
} else { } else {
if (m->quicksandDepth < 1.1f) { if (m->quicksandDepth < 1.1f) {
@ -338,6 +338,11 @@ s32 perform_ground_step(struct MarioState *m) {
smlua_call_event_hooks_mario_param(HOOK_BEFORE_PHYS_STEP, m); smlua_call_event_hooks_mario_param(HOOK_BEFORE_PHYS_STEP, m);
if (gServerSettings.enableCheats && gCheats.superSpeed && m->playerIndex == 0) {
m->vel[0] *= SUPER_SPEED_MULTIPLIER;
m->vel[2] *= SUPER_SPEED_MULTIPLIER;
}
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
Vec3f step = { Vec3f step = {
m->floor->normal.y * (m->vel[0] / 4.0f), m->floor->normal.y * (m->vel[0] / 4.0f),
@ -684,6 +689,11 @@ s32 perform_air_step(struct MarioState *m, u32 stepArg) {
smlua_call_event_hooks_mario_param(HOOK_BEFORE_PHYS_STEP, m); smlua_call_event_hooks_mario_param(HOOK_BEFORE_PHYS_STEP, m);
if (gServerSettings.enableCheats && gCheats.superSpeed && m->playerIndex == 0) {
m->vel[0] *= SUPER_SPEED_MULTIPLIER;
m->vel[2] *= SUPER_SPEED_MULTIPLIER;
}
m->wall = NULL; m->wall = NULL;
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {

View file

@ -23,6 +23,7 @@
#include "engine/math_util.h" #include "engine/math_util.h"
#include "pc/network/network.h" #include "pc/network/network.h"
#include "pc/lua/smlua.h" #include "pc/lua/smlua.h"
#include "pc/cheats.h"
/** /**
* Flags controlling what debug info is displayed. * Flags controlling what debug info is displayed.
@ -296,6 +297,10 @@ void bhv_mario_update(void) {
particleFlags |= gMarioState->particleFlags; particleFlags |= gMarioState->particleFlags;
gCurrentObject->oMarioParticleFlags = particleFlags; gCurrentObject->oMarioParticleFlags = particleFlags;
if (gServerSettings.enableCheats && gCheats.rapidFireA && gMarioState->playerIndex == 0) {
gMarioState->controller->buttonDown &= ~A_BUTTON;
}
// This code is meant to preserve old Lua mods' ability to set overridePaletteIndex and paletteIndex and still work // This code is meant to preserve old Lua mods' ability to set overridePaletteIndex and paletteIndex and still work
// as they expected. USE_REAL_PALETTE_VAR is meant to help support cases where mods will do: // as they expected. USE_REAL_PALETTE_VAR is meant to help support cases where mods will do:
// np.overridePaletteIndex = np.paletteIndex // np.overridePaletteIndex = np.paletteIndex

View file

@ -1,3 +1,3 @@
#include "cheats.h" #include "cheats.h"
struct CheatList Cheats; struct Cheats gCheats;

View file

@ -2,16 +2,21 @@
#define _CHEATS_H #define _CHEATS_H
#include <stdbool.h> #include <stdbool.h>
#include "network/network.h"
struct CheatList { #define SUPER_SPEED_MULTIPLIER 4
bool enabled;
struct Cheats {
bool moonJump; bool moonJump;
bool godMode; bool godMode;
bool infiniteLives; bool infiniteLives;
bool superSpeed; bool superSpeed;
bool responsive; bool responsiveControls;
bool rapidFireA;
bool alwaysTripleJump;
bool bljAnywhere;
}; };
extern struct CheatList Cheats; extern struct Cheats gCheats;
#endif // _CHEATS_H #endif // _CHEATS_H

View file

@ -71,7 +71,7 @@ void parse_cli_opts(int argc, char* argv[]) {
} }
} else if (strcmp(argv[i], "--cheats") == 0) // Enable cheats menu } else if (strcmp(argv[i], "--cheats") == 0) // Enable cheats menu
Cheats.enabled = true; gServerSettings.enableCheats = true;
else if (strcmp(argv[i], "--poolsize") == 0) // Main pool size else if (strcmp(argv[i], "--poolsize") == 0) // Main pool size
arg_uint("--poolsize", argv[++i], &gCLIOpts.PoolSize); arg_uint("--poolsize", argv[++i], &gCLIOpts.PoolSize);

View file

@ -2,7 +2,7 @@
#include "pc/cheats.h" #include "pc/cheats.h"
void djui_panel_cheats_create(struct DjuiBase* caller) { void djui_panel_cheats_create(struct DjuiBase* caller) {
f32 bodyHeight = 32 * 5 + 64 * 1 + 16 * 6; f32 bodyHeight = 32 * 8 + 64 * 1 + 16 * 9;
struct DjuiBase* defaultBase = NULL; struct DjuiBase* defaultBase = NULL;
struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\C\\#1be700\\H\\#00b3ff\\E\\#ffef00\\A\\#ff0800\\T\\#1be700\\S"); struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\C\\#1be700\\H\\#00b3ff\\E\\#ffef00\\A\\#ff0800\\T\\#1be700\\S");
@ -10,28 +10,43 @@ void djui_panel_cheats_create(struct DjuiBase* caller) {
{ {
{ {
struct DjuiCheckbox* checkbox = djui_checkbox_create(&body->base, "Moon jump", &Cheats.moonJump); struct DjuiCheckbox* checkbox = djui_checkbox_create(&body->base, "Moon Jump", &gCheats.moonJump);
djui_base_set_size_type(&checkbox->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); djui_base_set_size_type(&checkbox->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox->base, 1.0f, 32); djui_base_set_size(&checkbox->base, 1.0f, 32);
defaultBase = &checkbox->base; defaultBase = &checkbox->base;
} }
{ {
struct DjuiCheckbox* checkbox = djui_checkbox_create(&body->base, "God mode", &Cheats.godMode); struct DjuiCheckbox* checkbox = djui_checkbox_create(&body->base, "God Mode", &gCheats.godMode);
djui_base_set_size_type(&checkbox->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); djui_base_set_size_type(&checkbox->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox->base, 1.0f, 32); djui_base_set_size(&checkbox->base, 1.0f, 32);
} }
{ {
struct DjuiCheckbox* checkbox = djui_checkbox_create(&body->base, "Infinite lives", &Cheats.infiniteLives); struct DjuiCheckbox* checkbox = djui_checkbox_create(&body->base, "Infinite Lives", &gCheats.infiniteLives);
djui_base_set_size_type(&checkbox->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); djui_base_set_size_type(&checkbox->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox->base, 1.0f, 32); djui_base_set_size(&checkbox->base, 1.0f, 32);
} }
{ {
struct DjuiCheckbox* checkbox = djui_checkbox_create(&body->base, "Super speed", &Cheats.superSpeed); struct DjuiCheckbox* checkbox = djui_checkbox_create(&body->base, "Super Speed", &gCheats.superSpeed);
djui_base_set_size_type(&checkbox->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); djui_base_set_size_type(&checkbox->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox->base, 1.0f, 32); djui_base_set_size(&checkbox->base, 1.0f, 32);
} }
{ {
struct DjuiCheckbox* checkbox = djui_checkbox_create(&body->base, "Responsive controls", &Cheats.responsive); struct DjuiCheckbox* checkbox = djui_checkbox_create(&body->base, "Responsive Controls", &gCheats.responsiveControls);
djui_base_set_size_type(&checkbox->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox->base, 1.0f, 32);
}
{
struct DjuiCheckbox* checkbox = djui_checkbox_create(&body->base, "Rapid Fire (A)", &gCheats.rapidFireA);
djui_base_set_size_type(&checkbox->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox->base, 1.0f, 32);
}
{
struct DjuiCheckbox* checkbox = djui_checkbox_create(&body->base, "BLJ Anywhere", &gCheats.bljAnywhere);
djui_base_set_size_type(&checkbox->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox->base, 1.0f, 32);
}
{
struct DjuiCheckbox* checkbox = djui_checkbox_create(&body->base, "Always Triple Jump", &gCheats.alwaysTripleJump);
djui_base_set_size_type(&checkbox->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); djui_base_set_size_type(&checkbox->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox->base, 1.0f, 32); djui_base_set_size(&checkbox->base, 1.0f, 32);
} }

View file

@ -36,7 +36,7 @@ void djui_panel_pause_create(struct DjuiBase* caller) {
if (gDjuiChatBoxFocus) { djui_chat_box_toggle(); } if (gDjuiChatBoxFocus) { djui_chat_box_toggle(); }
f32 bodyHeight = 64 * 5 + 16 * 4; f32 bodyHeight = 64 * 5 + 16 * 4;
if (Cheats.enabled) { bodyHeight += 64 + 16; } if (gServerSettings.enableCheats) { bodyHeight += 64 + 16; }
struct DjuiBase* defaultBase = NULL; struct DjuiBase* defaultBase = NULL;
struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\P\\#1be700\\A\\#00b3ff\\U\\#ffef00\\S\\#ff0800\\E"); struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\P\\#1be700\\A\\#00b3ff\\U\\#ffef00\\S\\#ff0800\\E");
@ -65,7 +65,7 @@ void djui_panel_pause_create(struct DjuiBase* caller) {
djui_interactable_hook_click(&button3->base, djui_panel_options_create); djui_interactable_hook_click(&button3->base, djui_panel_options_create);
defaultBase = &button3->base; defaultBase = &button3->base;
if (Cheats.enabled) { if (gServerSettings.enableCheats) {
struct DjuiButton* button4 = djui_button_create(&body->base, "Cheats"); struct DjuiButton* button4 = djui_button_create(&body->base, "Cheats");
djui_base_set_size_type(&button4->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); djui_base_set_size_type(&button4->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button4->base, 1.0f, 64); djui_base_set_size(&button4->base, 1.0f, 64);

View file

@ -111,7 +111,6 @@ bool network_init(enum NetworkType inNetworkType) {
#else #else
gServerSettings.headlessServer = 0; gServerSettings.headlessServer = 0;
#endif #endif
Cheats.enabled = gServerSettings.enableCheats;
// initialize the network system // initialize the network system
gNetworkSentJoin = false; gNetworkSentJoin = false;

View file

@ -181,8 +181,6 @@ void network_receive_join(struct Packet* p) {
packet_read(p, eeprom, sizeof(u8) * 512); packet_read(p, eeprom, sizeof(u8) * 512);
packet_read(p, &modCount, sizeof(u8)); packet_read(p, &modCount, sizeof(u8));
Cheats.enabled = gServerSettings.enableCheats;
struct StringLinkedList head = { 0 }; struct StringLinkedList head = { 0 };
for (s32 i = 0; i < modCount; i++) { for (s32 i = 0; i < modCount; i++) {
char* modName = (char*) &p->buffer[p->cursor]; char* modName = (char*) &p->buffer[p->cursor];