Flying

From Ukikipedia
Revision as of 21:21, 1 August 2023 by Icecream17 (talk | contribs) (→‎Behavior: unimportant)
Jump to navigation Jump to search
Flying
Properties
Hex 0x10880899
Action Flags air, diving, attacking, swimming/flying
Action Group Airborne
ID 0x099
Transitions
Into Airborner cancels: Water Plunge, Squished, Vertical Wind (theoretically), (Technically, because of the flying triple jump code): Double Jump Land, Lava Boost (theoretically), non cancel: Ground Pound, Freefall, Dive Slide, Backwards Air Kb, Lava Boost (again) (theoretically)
Out of Shot From Cannon, Flying Triple Jump, when spawning in some levels like Tower of the Wing Cap
Other
Animation 0x5B fly from cannon, 0xCF forwards spinning flip, 0x29 wing cap fly


Flying is an action that can occurs when Mario triple jumps or does a cannon shot while wearing the wing cap.

Entering flying

  • Cannon shot: when y vel < 0 (and Mario does not cancel) (Action argument: 0)
  • Flying Triple Jump: when y vel < 4 (and Mario does not cancel, dive, or ground pound) (Action argument: 1)

Behavior

As with all airborne actions, a variety of "cancels" are checked prior to actually performing any airborne action. See Jump#Airborne cancels.

Then:

  1. If Z is pressed
    1. If Mario's camera mode is CAMERA_MODE_BEHIND_MARIO, set_camera_mode to m->area->camera->defMode
    2. Ground Pound
  2. If Mario is not wearing the wing cap
    1. If Mario's camera mode is CAMERA_MODE_BEHIND_MARIO, set_camera_mode to m->area->camera->defMode
    2. Freefall
  3. If Mario's camera mode is not CAMERA_MODE_BEHIND_MARIO, set_camera_mode to CAMERA_MODE_BEHIND_MARIO
  4. If the action state is 0
    1. If the action argument is 0 (was shot from cannon), set Mario's animation to MARIO_ANIM_FLY_FROM_CANNON, else set Mario's animation to MARIO_ANIM_FORWARD_SPINNING_FLIP
    2. If the animation finished,
      1. If the action argument is 2 (spawned in), load_level_init_text and set action argument to 1
      2. Set Mario's animation to MARIO_ANIM_WING_CAP_FLY
      3. Set action state to 1
  5. Call update_flying
  6. switch Movement_steps#Perform_Air_Step:
    1. air step none:
      1. Update graphics (camera) angle to be behind Mario
      2. Set action timer to 0
    2. air step land:
      1. Set action to Dive Slide
      2. Set animation to MARIO_ANIM_DIVE
      3. Set animation frame to 7
      4. Set facing angle (x) to 0
      5. Set camera mode to m->area->camera->defMode
    3. air step hit wall:
      1. todo
      2. if wall is not null, stuff, Backwards Air Kb
      3. else, stuff (but no knockback, this is probably out of bounds)
    4. air step hit lava wall:
      1. stop holding, stop riding, Lava Boost
  7. finally, play the flying sound (adjust sound for speed)

I am too lazy to describe the exact details of update_flying, so here is the code

/**
 * Return the value 'current' after it tries to approach target, going up at
 * most 'inc' and going down at most 'dec'.
 */
s32 approach_s32(s32 current, s32 target, s32 inc, s32 dec) {
    //! If target is close to the max or min s32, then it's possible to overflow
    // past it without stopping.

    if (current < target) {
        current += inc;
        if (current > target) {
            current = target;
        }
    } else {
        current -= dec;
        if (current < target) {
            current = target;
        }
    }
    return current;
}

void update_flying_yaw(struct MarioState *m) {
    s16 targetYawVel = -(s16)(m->controller->stickX * (m->forwardVel / 4.0f));

    if (targetYawVel > 0) {
        if (m->angleVel[1] < 0) {
            m->angleVel[1] += 0x40;
            if (m->angleVel[1] > 0x10) {
                m->angleVel[1] = 0x10;
            }
        } else {
            m->angleVel[1] = approach_s32(m->angleVel[1], targetYawVel, 0x10, 0x20);
        }
    } else if (targetYawVel < 0) {
        if (m->angleVel[1] > 0) {
            m->angleVel[1] -= 0x40;
            if (m->angleVel[1] < -0x10) {
                m->angleVel[1] = -0x10;
            }
        } else {
            m->angleVel[1] = approach_s32(m->angleVel[1], targetYawVel, 0x20, 0x10);
        }
    } else {
        m->angleVel[1] = approach_s32(m->angleVel[1], 0, 0x40, 0x40);
    }

    m->faceAngle[1] += m->angleVel[1];
    m->faceAngle[2] = 20 * -m->angleVel[1];
}

void update_flying_pitch(struct MarioState *m) {
    s16 targetPitchVel = -(s16)(m->controller->stickY * (m->forwardVel / 5.0f));

    if (targetPitchVel > 0) {
        if (m->angleVel[0] < 0) {
            m->angleVel[0] += 0x40;
            if (m->angleVel[0] > 0x20) {
                m->angleVel[0] = 0x20;
            }
        } else {
            m->angleVel[0] = approach_s32(m->angleVel[0], targetPitchVel, 0x20, 0x40);
        }
    } else if (targetPitchVel < 0) {
        if (m->angleVel[0] > 0) {
            m->angleVel[0] -= 0x40;
            if (m->angleVel[0] < -0x20) {
                m->angleVel[0] = -0x20;
            }
        } else {
            m->angleVel[0] = approach_s32(m->angleVel[0], targetPitchVel, 0x40, 0x20);
        }
    } else {
        m->angleVel[0] = approach_s32(m->angleVel[0], 0, 0x40, 0x40);
    }
}

void update_flying(struct MarioState *m) {
    UNUSED u8 filler[4];

    update_flying_pitch(m);
    update_flying_yaw(m);

    m->forwardVel -= 2.0f * ((f32) m->faceAngle[0] / 0x4000) + 0.1f;
    m->forwardVel -= 0.5f * (1.0f - coss(m->angleVel[1]));

    if (m->forwardVel < 0.0f) {
        m->forwardVel = 0.0f;
    }

    if (m->forwardVel > 16.0f) {
        m->faceAngle[0] += (m->forwardVel - 32.0f) * 6.0f;
    } else if (m->forwardVel > 4.0f) {
        m->faceAngle[0] += (m->forwardVel - 32.0f) * 10.0f;
    } else {
        m->faceAngle[0] -= 0x400;
    }

    m->faceAngle[0] += m->angleVel[0];

    if (m->faceAngle[0] > 0x2AAA) {
        m->faceAngle[0] = 0x2AAA;
    }
    if (m->faceAngle[0] < -0x2AAA) {
        m->faceAngle[0] = -0x2AAA;
    }

    m->vel[0] = m->forwardVel * coss(m->faceAngle[0]) * sins(m->faceAngle[1]);
    m->vel[1] = m->forwardVel * sins(m->faceAngle[0]);
    m->vel[2] = m->forwardVel * coss(m->faceAngle[0]) * coss(m->faceAngle[1]);

    m->slideVelX = m->vel[0];
    m->slideVelZ = m->vel[2];
}