Super Mario 64 has been decompiled

CrashOveride

Well-Known Member
Newcomer
Joined
May 29, 2017
Messages
50
Trophies
0
XP
127
Country
United States
You can rewrite the graphics routines to not use F3D if you're porting this, and it's already possible to dump graphics to a higher level format while emulating.

You almost don't have to touch the F3D GBI at all. Only a very small number of graphics are dynamically generated.

So you're saying you'd rather use crappy export from VRML than editing the raw displaylist data?
 

Ecchi95

Well-Known Member
OP
Member
Joined
Jul 7, 2019
Messages
121
Trophies
0
Age
29
XP
891
Country
United States
So you're saying you'd rather use crappy export from VRML than editing the raw displaylist data?
My point is you don't have to use the original models. You could make all new models if you're doing an enhanced port. (Original code, brand new assets.)
 

Zacharybinx34

Active Member
Newcomer
Joined
Aug 19, 2010
Messages
27
Trophies
0
XP
218
Country
United States
In theory, yes, in practice, it still would require some work, because one has to re-model everything, or just import models from newer Mario games, but again, that requires some extra time to be worked, because the developers back then, made tricky workarounds for many things that were still unknown for it's time, after all, 3D Videogame development was on its early days. For example, many people doesn't know that Mario's body isn't textured at all, those are raw colored polygons and nothing else lol.



Well, I would need some time to know the 3DS internals and capabilities homebrew-wise, such as what control we have on the system so far. I believe that as today we have full control, so anything is possible inside that tiny but marvelous handheld. I will try to play around with the source code on PC first, and maybe, little maybe I will look if I can port that to the 3DS, if someone can put me in the right direction it would be much appreciated.

I would LOVE to see an upgraded Camera + Mario 64 looking like Mario Sunshine/Odyssey :)
 

Ecchi95

Well-Known Member
OP
Member
Joined
Jul 7, 2019
Messages
121
Trophies
0
Age
29
XP
891
Country
United States
>My point is you don't have to use the original models. You could make all new models if you're doing an enhanced port. (Original code, brand new assets.

Hard when a lot of the code is tied to the graphics
You can get rid of that code. You only really need the logic for Mario and the things he interacts with.
 

mountainflaw

Member
Newcomer
Joined
Jul 11, 2018
Messages
22
Trophies
0
Age
34
XP
107
Country
Australia
I never said it was impossible. However as someone who actually has worked on the project, I can tell you removing the n64 graphicsisms from the main code isn't fun. Also, there is much much MUCH more than just Mario's code you'd want, especially since it's all intertwined.
 

CrashOveride

Well-Known Member
Newcomer
Joined
May 29, 2017
Messages
50
Trophies
0
XP
127
Country
United States
>You can get rid of that code. You only really need the logic for Mario and the things he interacts with.

what? have you even looked at the code at all?
 
  • Like
Reactions: AlanJohn

Ecchi95

Well-Known Member
OP
Member
Joined
Jul 7, 2019
Messages
121
Trophies
0
Age
29
XP
891
Country
United States
>You can get rid of that code. You only really need the logic for Mario and the things he interacts with.

what? have you even looked at the code at all?
Yes, I have. I couldn't have made the file list for one of the src directories if I didn't have it.

The most important parts are the player code and the code for all the animate and inanimate objects they interact with. You can abstract out the N64-dependent stuff. You just reference it to get the gist of what it's trying to do.
 

CrashOveride

Well-Known Member
Newcomer
Joined
May 29, 2017
Messages
50
Trophies
0
XP
127
Country
United States
I didn't ask if you had the code, I asked have you bothered to read it at all.

Using a search function for .c and .asm is not an answer

I consider arguing with @mountainflaw, someone who actively participated in the decomp process, useless
 
Last edited by CrashOveride,

Ecchi95

Well-Known Member
OP
Member
Joined
Jul 7, 2019
Messages
121
Trophies
0
Age
29
XP
891
Country
United States
I didn't ask if you had the code, I asked have you bothered to read it at all.

Using a search function for .c and .asm is not an answer

I consider arguing with @mountainflaw, someone who actively participated in the decomp process, useless
YES, I HAVE. Look at the files in src/behaviors. Not too many N64 graphics things in them: (you can REFERENCE the graphics stuff in the other files to get the GIST of it instead of faithfully doing every little thing)

(what @mountainflaw is saying is irrelevant depending on how much accuracy you want to trade)


Code:
/**
 * Behavior for bhvEnemyLakitu.
 * Lakitu comes before it spawned spinies in processing order.
 * TODO: bhvCloud processing oredr
 */


/**
 * Hitbox for evil lakitu.
 */
static struct ObjectHitbox sEnemyLakituHitbox =
{
    /* interactType:      */ INTERACT_HIT_FROM_BELOW,
    /* downOffset:        */ 0,
    /* damageOrCoinValue: */ 2,
    /* health:            */ 0,
    /* numLootCoins:      */ 5,
    /* radius:            */ 50,
    /* height:            */ 50,
    /* hurtboxRadius:     */ 40,
    /* hurtboxHeight:     */ 50,
};


/**
 * Wait for mario to approach, then spawn the cloud and become visible.
 */
static void enemy_lakitu_act_uninitialized(void)
{
    if (o->oDistanceToMario < 2000.0f)
    {
        spawn_object_relative_with_scale(
            CLOUD_BP_LAKITU_CLOUD,
            0, 0, 0,
            2.0f,
            o,
            MODEL_MIST,
            bhvCloud);

        obj_unhide();
        o->oAction = ENEMY_LAKITU_ACT_MAIN;
    }
}

/**
 * Accelerate toward mario vertically.
 */
static void enemy_lakitu_update_vel_y(f32 offsetY)
{
    // In order to encourage oscillation, pass mario by a small margin before
    // accelerating the opposite direction
    f32 margin;
    if (o->oVelY < 0.0f)
    {
        margin = -3.0f;
    }
    else
    {
        margin = 3.0f;
    }

    if (o->oPosY < gMarioObject->oPosY + offsetY + margin)
    {
        obj_y_vel_approach(4.0f, 0.4f);
    }
    else
    {
        obj_y_vel_approach(-4.0f, 0.4f);
    }
}

/**
 * Control speed based on distance to mario, turn toward mario, and change move
 * angle toward mario.
 */
static void enemy_lakitu_update_speed_and_angle(void)
{
    f32 minSpeed;
    s16 turnSpeed;

    f32 distToMario = o->oDistanceToMario;
    if (distToMario > 500.0f)
    {
        distToMario = 500.0f;
    }

    // Move faster the farther away mario is and the faster mario is moving
    if ((minSpeed = 1.2f * gMarioStates[0].forwardVel) < 8.0f)
    {
        minSpeed = 8.0f;
    }
    o->oForwardVel = distToMario * 0.04f;
    clamp_f32(&o->oForwardVel, minSpeed, 40.0f);

    // Accelerate toward mario vertically
    enemy_lakitu_update_vel_y(300.0f);

    // Turn toward mario except right after throwing a spiny
    if (o->oEnemyLakituFaceForwardCountdown != 0)
    {
        o->oEnemyLakituFaceForwardCountdown -= 1;
    }
    else
    {
        obj_face_yaw_approach(o->oAngleToMario, 0x600);
    }

    // Change move angle toward mario faster when farther from mario
    turnSpeed = (s16)(distToMario * 2.0f);
    clamp_s16(&turnSpeed, 0xC8, 0xFA0);
    obj_rotate_yaw_toward(o->oAngleToMario, turnSpeed);
}

/**
 * When close enough to mario and facing roughly toward him, spawn a spiny and
 * hold it, then enter the hold spiny sub-action.
 */
static void enemy_lakitu_sub_act_no_spiny(void)
{
    func_8029ED38(1);

    if (o->oEnemyLakituSpinyCooldown != 0)
    {
        o->oEnemyLakituSpinyCooldown -= 1;
    }
    else if (o->oEnemyLakituNumSpinies < 3 &&
        o->oDistanceToMario < 800.0f &&
        abs_angle_diff(o->oAngleToMario, o->oFaceAngleYaw) < 0x4000)
    {
        struct Object *spiny = spawn_object(o, MODEL_SPINY_BALL, bhvSpiny);
        if (spiny != NULL)
        {
            o->prevObj = spiny;
            spiny->oAction = SPINY_ACT_HELD_BY_LAKITU;

            func_8029EE20(spiny, spiny_egg_seg5_anims_050157E4, 0);

            o->oEnemyLakituNumSpinies += 1;
            o->oSubAction = ENEMY_LAKITU_SUB_ACT_HOLD_SPINY;
            o->oEnemyLakituSpinyCooldown = 30;
        }
    }
}

/**
 * When close to mario and facing toward him or when mario gets far enough away,
 * enter the throw spiny sub-action.
 */
static void enemy_lakitu_sub_act_hold_spiny(void)
{
    func_802F927C(3);

    if (o->oEnemyLakituSpinyCooldown != 0)
    {
        o->oEnemyLakituSpinyCooldown -= 1;
    }
    // TODO: Check if anything interesting happens if we bypass this with speed
    else if (o->oDistanceToMario > o->oDrawingDistance - 100.0f ||
        (o->oDistanceToMario < 500.0f &&
            abs_angle_diff(o->oAngleToMario, o->oFaceAngleYaw) < 0x2000))
    {
        o->oSubAction = ENEMY_LAKITU_SUB_ACT_THROW_SPINY;
        o->oEnemyLakituFaceForwardCountdown = 20;
    }
}

/**
 * Throw the spiny, then enter the no spiny sub-action.
 */
static void enemy_lakitu_sub_act_throw_spiny(void)
{
    if (func_802F92EC(2, 2))
    {
        PlaySound2(SOUND_OBJECT_EVILLAKITUTHROW);
        o->prevObj = NULL;
    }

    if (func_8029F788())
    {
        o->oSubAction = ENEMY_LAKITU_SUB_ACT_NO_SPINY;
        o->oEnemyLakituSpinyCooldown = random_linear_offset(100, 100);
    }
}

/**
 * Main update function.
 */
static void enemy_lakitu_act_main(void)
{
    PlaySound(SOUND_CH6_UNKNOWN002);

    obj_update_floor_and_walls();

    enemy_lakitu_update_speed_and_angle();
    if (o->oMoveFlags & OBJ_MOVE_HIT_WALL)
    {
        o->oMoveAngleYaw = obj_reflect_move_angle_off_wall();
    }

    obj_update_blinking(&o->oEnemyLakituBlinkTimer, 20, 40, 4);

    switch (o->oSubAction)
    {
    case ENEMY_LAKITU_SUB_ACT_NO_SPINY:    enemy_lakitu_sub_act_no_spiny();    break;
    case ENEMY_LAKITU_SUB_ACT_HOLD_SPINY:  enemy_lakitu_sub_act_hold_spiny();  break;
    case ENEMY_LAKITU_SUB_ACT_THROW_SPINY: enemy_lakitu_sub_act_throw_spiny(); break;
    }

    obj_move_standard(78);

    // Die and drop held spiny when attacked by mario
    if (obj_check_attacks(&sEnemyLakituHitbox, o->oAction))
    {
        // The spiny uses this as a signal to get thrown
        o->prevObj = NULL;
    }
}

/**
 * Update function for bhvEnemyLakitu.
 */
void bhv_enemy_lakitu_update(void)
{
    //PARTIAL_UPDATE

    treat_far_home_as_mario(2000.0f);

    switch (o->oAction)
    {
    case ENEMY_LAKITU_ACT_UNINITIALIZED: enemy_lakitu_act_uninitialized(); break;
    case ENEMY_LAKITU_ACT_MAIN:          enemy_lakitu_act_main();          break;
    }
}
 
Last edited by Ecchi95,

SuckerPunch32

New Member
Newbie
Joined
Jul 11, 2019
Messages
3
Trophies
0
XP
56
Country
United States
YES, I HAVE. Look at the files in src/behaviors. Not too many N64 graphics things in them: (you can REFERENCE the graphics stuff in the other files to get the GIST of it instead of faithfully doing every little thing)

(what @mountainflaw is saying is irrelevant depending on how much accuracy you want to trade)

Code:
/**
 * Behavior for bhvEnemyLakitu.
 * Lakitu comes before it spawned spinies in processing order.
 * TODO: bhvCloud processing oredr
 */


/**
 * Hitbox for evil lakitu.
 */
static struct ObjectHitbox sEnemyLakituHitbox =
{
    /* interactType:      */ INTERACT_HIT_FROM_BELOW,
    /* downOffset:        */ 0,
    /* damageOrCoinValue: */ 2,
    /* health:            */ 0,
    /* numLootCoins:      */ 5,
    /* radius:            */ 50,
    /* height:            */ 50,
    /* hurtboxRadius:     */ 40,
    /* hurtboxHeight:     */ 50,
};


/**
 * Wait for mario to approach, then spawn the cloud and become visible.
 */
static void enemy_lakitu_act_uninitialized(void)
{
    if (o->oDistanceToMario < 2000.0f)
    {
        spawn_object_relative_with_scale(
            CLOUD_BP_LAKITU_CLOUD,
            0, 0, 0,
            2.0f,
            o,
            MODEL_MIST,
            bhvCloud);

        obj_unhide();
        o->oAction = ENEMY_LAKITU_ACT_MAIN;
    }
}

/**
 * Accelerate toward mario vertically.
 */
static void enemy_lakitu_update_vel_y(f32 offsetY)
{
    // In order to encourage oscillation, pass mario by a small margin before
    // accelerating the opposite direction
    f32 margin;
    if (o->oVelY < 0.0f)
    {
        margin = -3.0f;
    }
    else
    {
        margin = 3.0f;
    }

    if (o->oPosY < gMarioObject->oPosY + offsetY + margin)
    {
        obj_y_vel_approach(4.0f, 0.4f);
    }
    else
    {
        obj_y_vel_approach(-4.0f, 0.4f);
    }
}

/**
 * Control speed based on distance to mario, turn toward mario, and change move
 * angle toward mario.
 */
static void enemy_lakitu_update_speed_and_angle(void)
{
    f32 minSpeed;
    s16 turnSpeed;

    f32 distToMario = o->oDistanceToMario;
    if (distToMario > 500.0f)
    {
        distToMario = 500.0f;
    }

    // Move faster the farther away mario is and the faster mario is moving
    if ((minSpeed = 1.2f * gMarioStates[0].forwardVel) < 8.0f)
    {
        minSpeed = 8.0f;
    }
    o->oForwardVel = distToMario * 0.04f;
    clamp_f32(&o->oForwardVel, minSpeed, 40.0f);

    // Accelerate toward mario vertically
    enemy_lakitu_update_vel_y(300.0f);

    // Turn toward mario except right after throwing a spiny
    if (o->oEnemyLakituFaceForwardCountdown != 0)
    {
        o->oEnemyLakituFaceForwardCountdown -= 1;
    }
    else
    {
        obj_face_yaw_approach(o->oAngleToMario, 0x600);
    }

    // Change move angle toward mario faster when farther from mario
    turnSpeed = (s16)(distToMario * 2.0f);
    clamp_s16(&turnSpeed, 0xC8, 0xFA0);
    obj_rotate_yaw_toward(o->oAngleToMario, turnSpeed);
}

/**
 * When close enough to mario and facing roughly toward him, spawn a spiny and
 * hold it, then enter the hold spiny sub-action.
 */
static void enemy_lakitu_sub_act_no_spiny(void)
{
    func_8029ED38(1);

    if (o->oEnemyLakituSpinyCooldown != 0)
    {
        o->oEnemyLakituSpinyCooldown -= 1;
    }
    else if (o->oEnemyLakituNumSpinies < 3 &&
        o->oDistanceToMario < 800.0f &&
        abs_angle_diff(o->oAngleToMario, o->oFaceAngleYaw) < 0x4000)
    {
        struct Object *spiny = spawn_object(o, MODEL_SPINY_BALL, bhvSpiny);
        if (spiny != NULL)
        {
            o->prevObj = spiny;
            spiny->oAction = SPINY_ACT_HELD_BY_LAKITU;

            func_8029EE20(spiny, spiny_egg_seg5_anims_050157E4, 0);

            o->oEnemyLakituNumSpinies += 1;
            o->oSubAction = ENEMY_LAKITU_SUB_ACT_HOLD_SPINY;
            o->oEnemyLakituSpinyCooldown = 30;
        }
    }
}

/**
 * When close to mario and facing toward him or when mario gets far enough away,
 * enter the throw spiny sub-action.
 */
static void enemy_lakitu_sub_act_hold_spiny(void)
{
    func_802F927C(3);

    if (o->oEnemyLakituSpinyCooldown != 0)
    {
        o->oEnemyLakituSpinyCooldown -= 1;
    }
    // TODO: Check if anything interesting happens if we bypass this with speed
    else if (o->oDistanceToMario > o->oDrawingDistance - 100.0f ||
        (o->oDistanceToMario < 500.0f &&
            abs_angle_diff(o->oAngleToMario, o->oFaceAngleYaw) < 0x2000))
    {
        o->oSubAction = ENEMY_LAKITU_SUB_ACT_THROW_SPINY;
        o->oEnemyLakituFaceForwardCountdown = 20;
    }
}

/**
 * Throw the spiny, then enter the no spiny sub-action.
 */
static void enemy_lakitu_sub_act_throw_spiny(void)
{
    if (func_802F92EC(2, 2))
    {
        PlaySound2(SOUND_OBJECT_EVILLAKITUTHROW);
        o->prevObj = NULL;
    }

    if (func_8029F788())
    {
        o->oSubAction = ENEMY_LAKITU_SUB_ACT_NO_SPINY;
        o->oEnemyLakituSpinyCooldown = random_linear_offset(100, 100);
    }
}

/**
 * Main update function.
 */
static void enemy_lakitu_act_main(void)
{
    PlaySound(SOUND_CH6_UNKNOWN002);

    obj_update_floor_and_walls();

    enemy_lakitu_update_speed_and_angle();
    if (o->oMoveFlags & OBJ_MOVE_HIT_WALL)
    {
        o->oMoveAngleYaw = obj_reflect_move_angle_off_wall();
    }

    obj_update_blinking(&o->oEnemyLakituBlinkTimer, 20, 40, 4);

    switch (o->oSubAction)
    {
    case ENEMY_LAKITU_SUB_ACT_NO_SPINY:    enemy_lakitu_sub_act_no_spiny();    break;
    case ENEMY_LAKITU_SUB_ACT_HOLD_SPINY:  enemy_lakitu_sub_act_hold_spiny();  break;
    case ENEMY_LAKITU_SUB_ACT_THROW_SPINY: enemy_lakitu_sub_act_throw_spiny(); break;
    }

    obj_move_standard(78);

    // Die and drop held spiny when attacked by mario
    if (obj_check_attacks(&sEnemyLakituHitbox, o->oAction))
    {
        // The spiny uses this as a signal to get thrown
        o->prevObj = NULL;
    }
}

/**
 * Update function for bhvEnemyLakitu.
 */
void bhv_enemy_lakitu_update(void)
{
    //PARTIAL_UPDATE

    treat_far_home_as_mario(2000.0f);

    switch (o->oAction)
    {
    case ENEMY_LAKITU_ACT_UNINITIALIZED: enemy_lakitu_act_uninitialized(); break;
    case ENEMY_LAKITU_ACT_MAIN:          enemy_lakitu_act_main();          break;
    }
}

That has nothing to do with the game or Mario, it's just behaviour code for an object. The rest of the game is basically tied to the N64 hardware. (Graphics, Audio, Engine (partially), etc.)
 
Last edited by SuckerPunch32,
  • Like
Reactions: CrashOveride

CrashOveride

Well-Known Member
Newcomer
Joined
May 29, 2017
Messages
50
Trophies
0
XP
127
Country
United States
>(you can REFERENCE the graphics stuff in the other files to get the GIST of it instead of faithfully doing every little thing)
Then what is the point of making a source port if you can just do it from scratch
 

Ecchi95

Well-Known Member
OP
Member
Joined
Jul 7, 2019
Messages
121
Trophies
0
Age
29
XP
891
Country
United States
>(you can REFERENCE the graphics stuff in the other files to get the GIST of it instead of faithfully doing every little thing)
Then what is the point of making a source port if you can just do it from scratch
You have the precise code for the behaviors. You can do everything else yourself, just referencing the original code for the gist.

You think when they made Ocarina of Time 3D they reproduced EVERYTHING? No.
 

SuckerPunch32

New Member
Newbie
Joined
Jul 11, 2019
Messages
3
Trophies
0
XP
56
Country
United States
You have the precise code for the behaviors. You can do everything else yourself, just referencing the original code for the gist.

You think when they made Ocarina of Time 3D they reproduced EVERYTHING? No.

So what you're saying is basically just port over the logic? That has already been done, here:
 
Last edited by SuckerPunch32,
  • Like
Reactions: Ecchi95

mountainflaw

Member
Newcomer
Joined
Jul 11, 2018
Messages
22
Trophies
0
Age
34
XP
107
Country
Australia
I'm not sure who said it was impossible, all I was trying to say is that it's still not a walk in the park for a port.
The port bad_boot made took about a week to make, getting the graphics and sound systems to work would probably be a pain in the ass that would take a month or two.
 
Last edited by mountainflaw,

Site & Scene News

Popular threads in this forum

General chit-chat
Help Users
    Psionic Roshambo @ Psionic Roshambo: https://www.youtube.com/watch?v=pkYA4rALqEE