the cutting room mirror

Unused Code

This is a sub-page of Super Mario 64 (Nintendo 64).

Unused Code#

Behavior Scripts#

Located in sm64/data/behavior_data.c, there exist a total of 10 unused behaviors that are never called in the final game. They're from older versions, so they might not function as they were originally intended to, or would have been used in a debug build instead.

Immediately escapes a behavior script. A similar one is used in-game, but the value is changed to 0x0A: Labelled as p_exit in the source code.

#define BREAK() \
    BC_B(0x0B)

Gets a random short value, right shifts it to the specified amount and adds the minimum value to it, then adds the value to the specified field: Labelled as p_addd_random in the source code.

#define ADD_INT_RAND_RSHIFT(field, min, rshift) \
    BC_BBH(0x17, field, min), \
    BC_H(rshift)

Behavior scripts that have no operation, presumably stubbed out due to being debug code. In the source code these are labelled "p_dprintf", "p_dprintx", and "p_dprintd" (dprint refers to the on-screen debug text print function).

#define CMD_NOP_1(field) \
    BC_BB(0x18, field)
    
#define CMD_NOP_2(field) \
    BC_BB(0x19, field)
    
#define CMD_NOP_3(field) \
    BC_BB(0x1A, field)

Leftovers for a behavior script that would animate 2d textures, this is handled with ADD_INT to oAnimState in the final. Labelled as p_softspriteanime in the source code.

#define CMD_NOP_4(field, value) \
    BC_BBH(0x24, field, value)

Sets the destination integer field to the sum of the values of the given integer fields: Labelled as p_WADDd in the source code.

#define SUM_INT(fieldDst, fieldSrc1, fieldSrc2) \
    BC_BBBB(0x20, fieldDst, fieldSrc1, fieldSrc2)

Marks the start of a loop that will repeat a limited number of times: Labelled as p_do_work in the source code.

#define BEGIN_REPEAT(count) \ 
    BC_BB(0x26, count)

Sets the object's interaction subtype: Labelled as p_setobjinfo in the source code.

#define SET_INTERACT_SUBTYPE(subtype) \
    BC_B(0x31), \
    BC_W(subtype)

Sets the specified field to an integer: Labelled as p_setlong in the source code.

#define SET_INT(field, value) \
    BC_BB(0x36, field), \
    BC_HH(0, value)

A unused function that directly jumps to a behavior command and resets the object's stack index.

static void goto_behavior_unused(const BehaviorScript *bhvAddr) {
    gCurBhvCommand = segmented_to_virtual(bhvAddr);
    gCurrentObject->bhvStackIndex = 0;
}

An unused function that does nothing.

static void stub_behavior_script_1(void) {
    for (;;) {
        ;
    }
}

An unused copy of exiting a behaviour script.

static s32 bhv_cmd_break(void) {
    return BHV_PROC_BREAK;
}

An function that marks the start of a loop that will repeat a certain number of times.

static s32 bhv_cmd_begin_repeat(void) {
    s32 count = BHV_CMD_GET_2ND_U8(0);

    cur_obj_bhv_stack_push(BHV_CMD_GET_ADDR_OF_CMD(1)); // Store address of the first command of the loop in the stack
    cur_obj_bhv_stack_push(count); // Store repeat count in the stack too

    gCurBhvCommand++;
    return BHV_PROC_CONTINUE;
}

A function that sets the specified field to an integer.

static s32 bhv_cmd_set_int(void) {
    u8 field = BHV_CMD_GET_2ND_U8(0);
    s32 value = BHV_CMD_GET_2ND_S16(1); // Taken from 2nd word instead of 1st

    cur_obj_set_int(field, value);

    gCurBhvCommand += 2; // Twice as long
    return BHV_PROC_CONTINUE;
}

3 functions that do nothing.

static s32 bhv_cmd_nop_1(void) {
    field = BHV_CMD_GET_2ND_U8(0);

    gCurBhvCommand++;
    return BHV_PROC_CONTINUE;
}

static s32 bhv_cmd_nop_3(void) {
    u8 field = BHV_CMD_GET_2ND_U8(0);

    gCurBhvCommand++;
    return BHV_PROC_CONTINUE;
}

static s32 bhv_cmd_nop_2(void) {
    u8 field = BHV_CMD_GET_2ND_U8(0);

    gCurBhvCommand++;
    return BHV_PROC_CONTINUE;
}

static s32 bhv_cmd_nop_4(void) {
    s16 field = BHV_CMD_GET_2ND_U8(0);
    s16 value = BHV_CMD_GET_2ND_S16(0);

    gCurBhvCommand++;
    return BHV_PROC_CONTINUE;
}

An incomplete behavior command that does not have an entry in the lookup table, and so no command number.

static void bhv_cmd_set_int_random_from_table(s32 tableSize) {
    u8 field = BHV_CMD_GET_2ND_U8(0);
    s32 table[16];
    s32 i;
    for (i = 0; i <= tableSize / 2; i += 2) {
        table[i] = BHV_CMD_GET_1ST_S16(i + 1);
        table[i + 1] = BHV_CMD_GET_2ND_S16(i + 1);
    }

    cur_obj_set_int(field, table[(s32)(tableSize * random_float())]);
}

Engine Scripts#

Graph Node#

Located in sm64/scr/engine/graph_node.c

Unused indentity and zero matrixs, Purpose unknown.

s16 identityMtx[4][4] = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } };
s16 zeroMtx[4][4] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } };

An unused 3-component vector type variable.

Vec3s gVec3sOne = { 1, 1, 1 };

An unused function to retrieve an object's current animation translation It assumes that it has x, y and z data in animations, which isn't always the case since some animation types only have vertical or lateral translation.

This might have been used for positioning the shadow under an object, which currently happens in-line in geo_process_shadow where it also accounts for animations without lateral translation.

void geo_retreive_animation_translation(struct GraphNodeObject *obj, Vec3f position) {
    struct Animation *animation = obj->animInfo.curAnim;

    if (animation != NULL) {
        u16 *attribute = segmented_to_virtual((void *) animation->index);
        s16 *values = segmented_to_virtual((void *) animation->values);

        s16 frame = obj->animInfo.animFrame;

        if (frame < 0) {
            frame = 0;
        }

        position[0] = (f32) values[retrieve_animation_index(frame, &attribute)];
        position[1] = (f32) values[retrieve_animation_index(frame, &attribute)];
        position[2] = (f32) values[retrieve_animation_index(frame, &attribute)];
    } else {
        vec3f_set(position, 0, 0, 0);
    }
}

An unused function to find the root of the geo node tree, which should be a GraphNodeRoot. If it is not for some reason, null is returned.

struct GraphNodeRoot *geo_find_root(struct GraphNode *graphNode) {
    struct GraphNodeRoot *resGraphNode = NULL;

    while (graphNode->parent != NULL) {
        graphNode = graphNode->parent;
    }

    if (graphNode->type == GRAPH_NODE_TYPE_ROOT) {
        resGraphNode = (struct GraphNodeRoot *) graphNode;
    }

    return resGraphNode;
}

Surface Loading#

Located in sm64/src/engine/surface_load.c

An unused function that supposedly loads the surface.

static void stub_surface_load_1(void) {
}

An unused function that does nothing.

static void 80383604(void) {
}

Audio Scripts#

Located in sm64/src/audio/data.c.

An unused audio cosine table.

u16 gAudioCosineTable[128] = {
    0x7FFF, 32764, 32757, 32744, 32727, 32704, 32677, 32644, 32607, 32564, 32517, 32464, 32407,
    32344,  32277, 32205, 32127, 32045, 31958, 31866, 31770, 31668, 31561, 31450, 31334, 31213,
    31087,  30957, 30822, 30682, 30537, 30388, 30234, 30075, 29912, 29744, 29572, 29395, 29214,
    29028,  28838, 28643, 28444, 28241, 28033, 27821, 27605, 27385, 27160, 26931, 26698, 26461,
    26220,  25975, 25726, 25473, 25216, 24956, 24691, 24423, 24151, 23875, 23596, 23313, 23026,
    22736,  22442, 22145, 21845, 21541, 21234, 20924, 20610, 20294, 19974, 19651, 19325, 18997,
    18665,  18331, 17993, 17653, 17310, 16965, 16617, 16266, 15913, 15558, 15200, 14840, 14477,
    14113,  13746, 13377, 13006, 12633, 12258, 11881, 11503, 11122, 10740, 10357, 9971,  9584,
    9196,   8806,  8415,  8023,  7630,  7235,  6839,  6442,  6044,  5646,  5246,  4845,  4444,
    4042,   3640,  3237,  2833,  2429,  2025,  1620,  1216,  810,   405,   0,
};

An unused debug function, Japanese only.

void 8031E4F0(void) {
    s32 i;

    stubbed_printf("AUTOSEQ ");
    stubbed_printf("%2x %2x <%5x : %5x / %5x>\n", gSeqLoadedPool.temporary.entries[0].id,
                   gSeqLoadedPool.temporary.entries[1].id, gSeqLoadedPool.temporary.entries[0].size,
                   gSeqLoadedPool.temporary.entries[1].size, gSeqLoadedPool.temporary.pool.size);

    stubbed_printf("AUTOBNK ");
    stubbed_printf("%2x %3x <%5x : %5x / %5x>\n", gBankLoadedPool.temporary.entries[0].id,
                   gBankLoadedPool.temporary.entries[1].id, gBankLoadedPool.temporary.entries[0].size,
                   gBankLoadedPool.temporary.entries[1].size, gBankLoadedPool.temporary.pool.size);

    stubbed_printf("STAYSEQ ");
    stubbed_printf("[%2x] <%5x / %5x>\n", gSeqLoadedPool.persistent.numEntries,
                   gSeqLoadedPool.persistent.pool.cur - gSeqLoadedPool.persistent.pool.start,
                   gSeqLoadedPool.persistent.pool.size);
    for (i = 0; (u32) i < gSeqLoadedPool.persistent.numEntries; i++) {
        stubbed_printf("%2x ", gSeqLoadedPool.persistent.entries[i].id);
    }
    stubbed_printf("\n");

    stubbed_printf("STAYBNK ");
    stubbed_printf("[%2x] <%5x / %5x>\n", gBankLoadedPool.persistent.numEntries,
                   gBankLoadedPool.persistent.pool.cur - gBankLoadedPool.persistent.pool.start,
                   gBankLoadedPool.persistent.pool.size);
    for (i = 0; (u32) i < gBankLoadedPool.persistent.numEntries; i++) {
        stubbed_printf("%2x ", gBankLoadedPool.persistent.entries[i].id);
    }
    stubbed_printf("\n\n");

    stubbed_printf("    0123456789ABCDEF0123456789ABCDEF01234567\n");
    stubbed_printf("--------------------------------------------\n");

    // gSeqLoadStatus/gBankLoadStatus, 4 entries at a time?
    stubbed_printf("SEQ ");
    for (i = 0; i < 40; i++) {
        stubbed_printf("%1x", 0);
    }
    stubbed_printf("\n");

    stubbed_printf("BNK ");
    for (i = 0; i < 40; i += 4) {
        stubbed_printf("%1x", 0);
    }
    stubbed_printf("\n");

    stubbed_printf("FIXHEAP ");
    stubbed_printf("%4x / %4x\n", 0, 0);
    stubbed_printf("DRVHEAP ");
    stubbed_printf("%5x / %5x\n", 0, 0);
    stubbed_printf("DMACACHE  %4d Blocks\n", 0);
    stubbed_printf("CHANNELS  %2d / MAX %3d \n", 0, 0);

    stubbed_printf("TEMPOMAX  %d\n", gTempoInternalToExternal / TEMPO_SCALE);
    stubbed_printf("TEMPO G0  %d\n", gSequencePlayers[SEQ_PLAYER_LEVEL].tempo / TEMPO_SCALE);
    stubbed_printf("TEMPO G1  %d\n", gSequencePlayers[SEQ_PLAYER_ENV].tempo / TEMPO_SCALE);
    stubbed_printf("TEMPO G2  %d\n", gSequencePlayers[SEQ_PLAYER_SFX].tempo / TEMPO_SCALE);
    stubbed_printf("DEBUGFLAG  %8x\n", gAudioErrorFlags);
}

An unused function that prints the audio frame count.

void 8031E568(void) {
    stubbed_printf("COUNT %8d\n", gAudioFrameCount);
}

Unused error strings.

const char ErrorStr1[] = "Error : Queue is not empty ( %x ) \n";
const char ErrorStr2[] = "specchg error\n";
void 8031FED0(u8 player, u32 bits, s8 arg2) {
    u8 i;

    if (arg2 < 0) {
        arg2 = -arg2;
    }

    for (i = 0; i < CHANNELS_MAX; i++) {
        if (gSequencePlayers[player].channels[i] != &gSequenceChannelNone) {
            if ((bits & 3) == 0) {
                gSequencePlayers[player].channels[i]->volumeScale = 1.0f;
            } else if ((bits & 1) != 0) {
                gSequencePlayers[player].channels[i]->volumeScale = (f32) arg2 / US_FLOAT(127.0);
            } else {
                gSequencePlayers[player].channels[i]->volumeScale =
                    US_FLOAT(1.0) - (f32) arg2 / US_FLOAT(127.0);
            }
        }
        bits >>= 2;
    }
}
void get_currently_playing_sound(u8 bank, u8 *numPlayingSounds, u8 *numSoundsInBank, u8 *soundId) {
    u8 i;
    u8 count = 0;

    for (i = 0; i < sMaxChannelsForSoundBank[bank]; i++) {
        if (sCurrentSound[bank][i] != 0xff) {
            count++;
        }
    }
    *numPlayingSounds = count;

    *numSoundsInBank = sNumSoundsInBank[bank];

    if (sCurrentSound[bank][0] != 0xff) {
        *soundId = (u8)(sSoundBanks[bank][sCurrentSound[bank][0]].soundBits >> SOUNDARGS_SHIFT_SOUNDID);
    } else {
        *soundId = 0xff;
    }
}

2 functions that do nothing, Japanese and US only.

void 80321460(s32 arg0, s32 arg1, s32 arg2, s32 arg3) {
}

void 80321474(s32 arg0) {
}

Debug Mode#

Present in sm64/src/game/debug.c.

To do:
Check 64DD version if these have code for that version.

Empty debug void functions, most likely from a debug build and later removed:

void debug_1(void) {
}

void debug_2(void) {
}

void debug_3(void) {
}

void debug_4(void) {
}

void stub_debug_5(void) {
}
static void try_change_debug_page(void) {
    if (gDebugInfoFlags & DEBUG_INFO_FLAG_DPRINT) {
        if ((gPlayer1Controller->buttonPressed & L_JPAD)
            && (gPlayer1Controller->buttonDown & (L_TRIG | R_TRIG))) {
            sDebugPage++;
        }
        if ((gPlayer1Controller->buttonPressed & R_JPAD)
            && (gPlayer1Controller->buttonDown & (L_TRIG | R_TRIG))) {
            sDebugPage--;
        }
        if (sDebugPage >= (DEBUG_PAGE_MAX + 1)) {
            sDebugPage = DEBUG_PAGE_MIN;
        }
        if (sDebugPage < DEBUG_PAGE_MIN) {
            sDebugPage = DEBUG_PAGE_MAX;
        }
    }
}

A debug enemy function:

void debug_enemy(s16 *enemyArr) {
    enemyArr[4] = gDebugInfo[DEBUG_PAGE_ENEMYINFO][1];
    enemyArr[5] = gDebugInfo[DEBUG_PAGE_ENEMYINFO][2];
    enemyArr[6] = gDebugInfo[DEBUG_PAGE_ENEMYINFO][3];
    enemyArr[7] = gDebugInfo[DEBUG_PAGE_ENEMYINFO][4];
}

A debug function that cycles through most of Bowser's actions:

static void bowser_debug_actions(void) {
    if (gDebugInfo[DEBUG_PAGE_ENEMYINFO][1] != 0) {
        o->oAction = sBowserDebugActions[gDebugInfo[DEBUG_PAGE_ENEMYINFO][2] & 0x0F];
        gDebugInfo[DEBUG_PAGE_ENEMYINFO][1] = 0;
    }
}

Area and Positional Checks#

Bob-omb Battlefield was supposed to have its own unique camera areas.

struct CameraTrigger sCamBOB[] = {
    {  1, cam_bob_tower, 2468, 2720, -4608, 3263, 1696, 3072, 0 },
    { -1, cam_bob_default_free_roam, 0, 0, 0, 0, 0, 0, 0 },
     NULL_TRIGGER
};