Flying
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)
- Spawning in, e.g, Tower of the Wing Cap: (Action argument: 2)
Behavior
As with all airborne actions, a variety of "cancels" are checked prior to actually performing any airborne action. See Jump#Airborne cancels.
Then:
- If Z is pressed
- If Mario's camera mode is CAMERA_MODE_BEHIND_MARIO, set_camera_mode to m->area->camera->defMode
- Ground Pound
- If Mario is not wearing the wing cap
- If Mario's camera mode is CAMERA_MODE_BEHIND_MARIO, set_camera_mode to m->area->camera->defMode
- Freefall
- If Mario's camera mode is not CAMERA_MODE_BEHIND_MARIO, set_camera_mode to CAMERA_MODE_BEHIND_MARIO
- If the action state is 0
- 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
- If the animation finished,
- If the action argument is 2 (spawned in), load_level_init_text and set action argument to 1
- Set Mario's animation to MARIO_ANIM_WING_CAP_FLY
- Set action state to 1
- Call
update_flying
- switch Movement_steps#Perform_Air_Step:
- air step none:
- Update graphics (camera) angle to be behind Mario
- Set action timer to 0
- air step land:
- Set action to Dive Slide
- Set animation to MARIO_ANIM_DIVE
- Set animation frame to 7
- Set facing angle (x) to 0
- Set camera mode to m->area->camera->defMode
- air step hit wall:
- todo
- if wall is not null, stuff, Backwards Air Kb
- else, stuff (but no knockback, this is probably out of bounds)
- air step hit lava wall:
- stop holding, stop riding, Lava Boost
- air step none:
- finally, play the flying sound (adjust sound for speed)
Notice that there is no code handling air steps for ledge grabbing or hanging on a ceiling, so such transitions are impossible.
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];
}