-- name: Extended Moveset -- incompatible: moveset -- description: Adds various new moves from games like Sunshine and Odyssey without replacing any existing ones.\n\nOriginal author: TheGag96 ------------------------ -- initialize actions -- ------------------------ ACT_SPIN_POUND_LAND = allocate_mario_action(ACT_GROUP_STATIONARY | ACT_FLAG_STATIONARY | ACT_FLAG_ATTACKING) ACT_ROLL = allocate_mario_action(ACT_GROUP_MOVING | ACT_FLAG_MOVING | ACT_FLAG_BUTT_OR_STOMACH_SLIDE) ACT_GROUND_POUND_JUMP = allocate_mario_action(ACT_GROUP_AIRBORNE | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION) ACT_SPIN_JUMP = allocate_mario_action(ACT_GROUP_AIRBORNE | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION) ACT_SPIN_POUND = allocate_mario_action(ACT_GROUP_AIRBORNE | ACT_FLAG_AIR | ACT_FLAG_ATTACKING) ACT_LEDGE_PARKOUR = allocate_mario_action(ACT_GROUP_AIRBORNE | ACT_FLAG_AIR) ACT_ROLL_AIR = allocate_mario_action(ACT_GROUP_AIRBORNE | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION) ACT_WALL_SLIDE = allocate_mario_action(ACT_GROUP_AIRBORNE | ACT_FLAG_AIR | ACT_FLAG_MOVING | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION) ACT_WATER_GROUND_POUND = allocate_mario_action(ACT_GROUP_SUBMERGED | ACT_FLAG_MOVING | ACT_FLAG_SWIMMING | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT | ACT_FLAG_ATTACKING) ACT_WATER_GROUND_POUND_LAND = allocate_mario_action(ACT_GROUP_SUBMERGED | ACT_FLAG_STATIONARY | ACT_FLAG_SWIMMING | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT) ACT_WATER_GROUND_POUND_STROKE = allocate_mario_action(ACT_GROUP_SUBMERGED | ACT_FLAG_MOVING | ACT_FLAG_SWIMMING | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT) ACT_WATER_GROUND_POUND_JUMP = allocate_mario_action(ACT_GROUP_SUBMERGED | ACT_FLAG_MOVING | ACT_FLAG_SWIMMING | ACT_FLAG_SWIMMING_OR_FLYING | ACT_FLAG_WATER_OR_TEXT) ----------------------------- -- initialize extra fields -- ----------------------------- ANGLE_QUEUE_SIZE = 9 SPIN_TIMER_SUCCESSFUL_INPUT = 4 gMarioStateExtras = {} for i=0,(MAX_PLAYERS-1) do gMarioStateExtras[i] = {} local m = gMarioStates[i] local e = gMarioStateExtras[i] e.angleDeltaQueue = {} for j=0,(ANGLE_QUEUE_SIZE-1) do e.angleDeltaQueue[j] = 0 end e.rotAngle = 0 e.boostTimer = 0 e.stickLastAngle = 0 e.spinDirection = 0 e.spinBufferTimer = 0 e.spinInput = 0 e.lastIntendedMag = 0 e.lastPos = {} e.lastPos.x = m.pos.x e.lastPos.y = m.pos.y e.lastPos.z = m.pos.z e.fakeSavedAction = 0 e.fakeSavedPrevAction = 0 e.fakeSavedActionTimer = 0 e.fakeWroteAction = 0 e.fakeSaved = false e.savedWallSlideHeight = 0 e.savedWallSlide = false end function limit_angle(a) return (a + 0x8000) % 0x10000 - 0x8000 end ---------- -- roll -- ---------- function update_roll_sliding_angle(m, accel, lossFactor) local floor = m.floor local slopeAngle = atan2s(floor.normal.z, floor.normal.x) local steepness = math.sqrt(floor.normal.x * floor.normal.x + floor.normal.z * floor.normal.z) m.slideVelX = m.slideVelX + accel * steepness * sins(slopeAngle) m.slideVelZ = m.slideVelZ + accel * steepness * coss(slopeAngle) m.slideVelX = m.slideVelX * lossFactor m.slideVelZ = m.slideVelZ * lossFactor m.slideYaw = atan2s(m.slideVelZ, m.slideVelX) local facingDYaw = limit_angle(m.faceAngle.y - m.slideYaw) local newFacingDYaw = facingDYaw if newFacingDYaw > 0 and newFacingDYaw <= 0x8000 then newFacingDYaw = newFacingDYaw - 0x800 if newFacingDYaw < 0 then newFacingDYaw = 0 end elseif newFacingDYaw >= -0x8000 and newFacingDYaw < 0 then newFacingDYaw = newFacingDYaw + 0x800 if newFacingDYaw > 0 then newFacingDYaw = 0 end end m.faceAngle.y = limit_angle(m.slideYaw + newFacingDYaw) m.vel.x = m.slideVelX m.vel.y = 0.0 m.vel.z = m.slideVelZ mario_update_moving_sand(m) mario_update_windy_ground(m) --! Speed is capped a frame late (butt slide HSG) m.forwardVel = math.sqrt(m.slideVelX * m.slideVelX + m.slideVelZ * m.slideVelZ) if m.forwardVel > 100.0 then m.slideVelX = m.slideVelX * 100.0 / m.forwardVel m.slideVelZ = m.slideVelZ * 100.0 / m.forwardVel end end function update_roll_sliding(m, stopSpeed) local stopped = 0 local intendedDYaw = m.intendedYaw - m.slideYaw local forward = coss(intendedDYaw) local sideward = sins(intendedDYaw) --! 10k glitch if forward < 0.0 and m.forwardVel >= 0.0 then forward = forward * (0.5 + 0.5 * m.forwardVel / 100.0) end local accel = 4.0 local lossFactor = 0.994 local oldSpeed = math.sqrt(m.slideVelX * m.slideVelX + m.slideVelZ * m.slideVelZ) --! This is uses trig derivatives to rotate Mario's speed. -- In vanilla, it was slightly off/asymmetric since it uses the new X speed, but the old -- Z speed. I've gone and fixed it here. local angleChange = (m.intendedMag / 32.0) * 0.6 local modSlideVelX = m.slideVelZ * angleChange * sideward * 0.05 local modSlideVelZ = m.slideVelX * angleChange * sideward * 0.05 m.slideVelX = m.slideVelX + modSlideVelX m.slideVelZ = m.slideVelZ - modSlideVelZ local newSpeed = math.sqrt(m.slideVelX * m.slideVelX + m.slideVelZ * m.slideVelZ) if oldSpeed > 0.0 and newSpeed > 0.0 then m.slideVelX = m.slideVelX * oldSpeed / newSpeed m.slideVelZ = m.slideVelZ * oldSpeed / newSpeed end update_roll_sliding_angle(m, accel, lossFactor) if m.playerIndex == 0 and mario_floor_is_slope(m) == 0 and m.forwardVel * m.forwardVel < stopSpeed * stopSpeed then mario_set_forward_vel(m, 0.0) stopped = 1 end return stopped end function act_roll(m) local e = gMarioStateExtras[m.playerIndex] local MAX_NORMAL_ROLL_SPEED = 50.0 local ROLL_BOOST_GAIN = 10.0 local ROLL_CANCEL_LOCKOUT_TIME = 10 local BOOST_LOCKOUT_TIME = 20 -- e.rotAngle is used for Mario's rotation angle during the roll (persists when going into ACT_ROLL_AIR and back) -- e.boostTimer is used for the boost lockout timer (persists when going into ACT_ROLL_AIR and back) -- m.actionTimer is used to lockout walk canceling out of rollout (reset each action switch) if m.actionTimer == 0 then if m.prevAction ~= ACT_ROLL_AIR then e.rotAngle = 0 e.boostTimer = 0 end elseif m.actionTimer >= ROLL_CANCEL_LOCKOUT_TIME or m.actionArg == 1 then if (m.input & INPUT_Z_DOWN) == 0 then return set_mario_action(m, ACT_WALKING, 0) end end if (m.input & INPUT_B_PRESSED) ~= 0 then queue_rumble_data_mario(m, 5, 80) return set_jumping_action(m, ACT_FORWARD_ROLLOUT, 0) end if (m.input & INPUT_A_PRESSED) ~= 0 then return set_jumping_action(m, ACT_LONG_JUMP, 0) end if (m.controller.buttonPressed & X_BUTTON) ~= 0 and m.actionTimer > 0 then m.vel.y = 19.0 play_mario_sound(m, SOUND_ACTION_TERRAIN_JUMP, 0) if e.boostTimer >= BOOST_LOCKOUT_TIME then e.boostTimer = 0 if m.forwardVel < MAX_NORMAL_ROLL_SPEED then mario_set_forward_vel(m, math.min(m.forwardVel + ROLL_BOOST_GAIN, MAX_NORMAL_ROLL_SPEED)) end m.particleFlags = m.particleFlags | PARTICLE_HORIZONTAL_STAR -- ! playing this after the call to play_mario_sound seems to matter in making this sound play play_sound(SOUND_ACTION_SPIN, m.marioObj.header.gfx.cameraToObject) end return set_mario_action(m, ACT_ROLL_AIR, m.actionArg) end set_mario_animation(m, MARIO_ANIM_FORWARD_SPINNING) if update_roll_sliding(m, 10.0) ~= 0 then return set_mario_action(m, ACT_CROUCH_SLIDE, 0) end common_slide_action(m, ACT_CROUCH_SLIDE, ACT_ROLL_AIR, MARIO_ANIM_FORWARD_SPINNING) e.rotAngle = e.rotAngle + (0x80 * m.forwardVel) if e.rotAngle > 0x10000 then e.rotAngle = e.rotAngle - 0x10000 end set_anim_to_frame(m, 10 * e.rotAngle / 0x10000) e.boostTimer = e.boostTimer + 1 m.actionTimer = m.actionTimer + 1 return 0 end function act_roll_air(m) local e = gMarioStateExtras[m.playerIndex] local MAX_NORMAL_ROLL_SPEED = 50.0 local ROLL_AIR_CANCEL_LOCKOUT_TIME = 15 if m.actionTimer == 0 then if m.prevAction ~= ACT_ROLL then e.rotAngle = 0 e.boostTimer = 0 end end if (m.input & INPUT_Z_DOWN) == 0 and m.actionTimer >= ROLL_AIR_CANCEL_LOCKOUT_TIME then return set_mario_action(m, ACT_FREEFALL, 0) end set_mario_animation(m, MARIO_ANIM_FORWARD_SPINNING) local air_step = perform_air_step(m, 0) if air_step == AIR_STEP_LANDED then if check_fall_damage_or_get_stuck(m, ACT_HARD_BACKWARD_GROUND_KB) == 0 then play_sound_and_spawn_particles(m, SOUND_ACTION_TERRAIN_STEP, 0) return set_mario_action(m, ACT_ROLL, m.actionArg) end elseif air_step == AIR_STEP_HIT_WALL then queue_rumble_data_mario(m, 5, 40) mario_bonk_reflection(m, false) m.faceAngle.y = m.faceAngle.y + 0x8000 if m.vel.y > 0.0 then m.vel.y = 0.0 end m.particleFlags = m.particleFlags | PARTICLE_VERTICAL_STAR return set_mario_action(m, ACT_BACKWARD_AIR_KB, 0) end e.rotAngle = e.rotAngle + 0x80 * m.forwardVel if e.rotAngle > 0x10000 then e.rotAngle = e.rotAngle - 0x10000 end set_anim_to_frame(m, 10 * e.rotAngle / 0x10000) e.boostTimer = e.boostTimer + 1 m.actionTimer = m.actionTimer + 1 return false end function update_roll(m) if m.action == ACT_DIVE_SLIDE then if (m.input & INPUT_ABOVE_SLIDE) == 0 then if (m.input & INPUT_Z_DOWN) ~= 0 and m.actionTimer < 2 then return set_mario_action(m, ACT_ROLL, 1) end end m.actionTimer = m.actionTimer + 1 end if m.action == ACT_LONG_JUMP_LAND then if (m.input & INPUT_Z_DOWN) ~= 0 and m.forwardVel > 15.0 and m.actionTimer < 1 then play_mario_landing_sound_once(m, SOUND_ACTION_TERRAIN_LANDING) return set_mario_action(m, ACT_ROLL, 1) end end if m.action == ACT_CROUCHING then if (m.controller.buttonPressed & X_BUTTON) ~= 0 then m.vel.y = 19.0 mario_set_forward_vel(m, 32.0) play_mario_sound(m, SOUND_ACTION_TERRAIN_JUMP, 0) play_sound(SOUND_ACTION_SPIN, m.marioObj.header.gfx.cameraToObject) return set_mario_action(m, ACT_ROLL_AIR, 0) end end if m.action == ACT_CROUCH_SLIDE then if (m.controller.buttonPressed & X_BUTTON) ~= 0 then m.vel.y = 19.0 mario_set_forward_vel(m, math.max(32, m.forwardVel)) play_mario_sound(m, SOUND_ACTION_TERRAIN_JUMP, 0) play_sound(SOUND_ACTION_SPIN, m.marioObj.header.gfx.cameraToObject) return set_mario_action(m, ACT_ROLL_AIR, 0) end end if m.action == ACT_GROUND_POUND_LAND then if (m.controller.buttonPressed & X_BUTTON) ~= 0 then mario_set_forward_vel(m, 60) play_sound(SOUND_ACTION_SPIN, m.marioObj.header.gfx.cameraToObject) return set_mario_action(m, ACT_ROLL, 0) end end end ---------- -- spin -- ---------- function mario_update_spin_input(m) local e = gMarioStateExtras[m.playerIndex] local rawAngle = atan2s(-m.controller.stickY, m.controller.stickX) e.spinInput = 0 -- prevent issues due to the frame going out of the dead zone registering the last angle as 0 if e.lastIntendedMag > 0.5 and m.intendedMag > 0.5 then local angleOverFrames = 0 local thisFrameDelta = 0 local i = 0 local newDirection = e.spinDirection local signedOverflow = 0 if rawAngle < e.stickLastAngle then if e.stickLastAngle - rawAngle > 0x8000 then signedOverflow = 1 end if signedOverflow ~= 0 then newDirection = 1 else newDirection = -1 end elseif rawAngle > e.stickLastAngle then if rawAngle - e.stickLastAngle > 0x8000 then signedOverflow = 1 end if signedOverflow ~= 0 then newDirection = -1 else newDirection = 1 end end if e.spinDirection ~= newDirection then for i=0,(ANGLE_QUEUE_SIZE-1) do e.angleDeltaQueue[i] = 0 end e.spinDirection = newDirection else for i=(ANGLE_QUEUE_SIZE-1),1,-1 do e.angleDeltaQueue[i] = e.angleDeltaQueue[i-1] angleOverFrames = angleOverFrames + e.angleDeltaQueue[i] end end if e.spinDirection < 0 then if signedOverflow ~= 0 then thisFrameDelta = math.floor((1.0*e.stickLastAngle + 0x10000) - rawAngle) else thisFrameDelta = e.stickLastAngle - rawAngle end elseif e.spinDirection > 0 then if signedOverflow ~= 0 then thisFrameDelta = math.floor(1.0*rawAngle + 0x10000 - e.stickLastAngle) else thisFrameDelta = rawAngle - e.stickLastAngle end end e.angleDeltaQueue[0] = thisFrameDelta angleOverFrames = angleOverFrames + thisFrameDelta if angleOverFrames >= 0xA000 then e.spinBufferTimer = SPIN_TIMER_SUCCESSFUL_INPUT end -- allow a buffer after a successful input so that you can switch directions if e.spinBufferTimer > 0 then e.spinInput = 1 e.spinBufferTimer = e.spinBufferTimer - 1 end else e.spinDirection = 0 e.spinBufferTimer = 0 end e.stickLastAngle = rawAngle e.lastIntendedMag = m.intendedMag end function act_spin_jump(m) local e = gMarioStateExtras[m.playerIndex] if m.actionTimer == 0 then -- determine clockwise/counter-clockwise spin if e.spinDirection < 0 then m.actionState = 1 end elseif m.actionTimer == 1 or m.actionTimer == 4 then play_sound(SOUND_ACTION_TWIRL, m.marioObj.header.gfx.cameraToObject) end local spinDirFactor = 1 -- negative for clockwise, positive for counter-clockwise if m.actionState == 1 then spinDirFactor = -1 end if (m.input & INPUT_B_PRESSED) ~= 0 then return set_mario_action(m, ACT_DIVE, 0) end if (m.input & INPUT_Z_PRESSED) ~= 0 then play_sound(SOUND_ACTION_TWIRL, m.marioObj.header.gfx.cameraToObject) m.vel.y = -50.0 mario_set_forward_vel(m, 0.0) -- choose which direction to be facing on land (practically random if no input) if (m.input & INPUT_NONZERO_ANALOG) ~= 0 then m.faceAngle.y = m.intendedYaw else m.faceAngle.y = limit_angle(e.rotAngle) end return set_mario_action(m, ACT_SPIN_POUND, m.actionState) end play_mario_sound(m, SOUND_ACTION_TERRAIN_JUMP, CHAR_SOUND_YAHOO) common_air_action_step(m, ACT_DOUBLE_JUMP_LAND, MARIO_ANIM_TWIRL, AIR_STEP_CHECK_HANG) e.rotAngle = e.rotAngle + 0x2867 if (e.rotAngle > 0x10000) then e.rotAngle = e.rotAngle - 0x10000 end if (e.rotAngle < -0x10000) then e.rotAngle = e.rotAngle + 0x10000 end m.marioObj.header.gfx.angle.y = limit_angle(m.marioObj.header.gfx.angle.y + (e.rotAngle * spinDirFactor)) m.actionTimer = m.actionTimer + 1 return false end function act_spin_jump_gravity(m) if (m.flags & MARIO_WING_CAP) ~= 0 and m.vel.y < 0.0 and (m.input & INPUT_A_DOWN) ~= 0 then m.marioBodyState.wingFlutter = 1 m.vel.y = m.vel.y - 0.7 if m.vel.y < -37.5 then m.vel.y = m.vel.y + 1.4 if m.vel.y > -37.5 then m.vel.y = -37.5 end end else if m.vel.y > 0 then m.vel.y = m.vel.y - 4 else m.vel.y = m.vel.y - 1.4 end if m.vel.y < -75.0 then m.vel.y = -75.0 end end return 0 end function act_spin_pound(m) local e = gMarioStateExtras[m.playerIndex] if m.actionTimer == 0 then m.actionState = m.actionArg end local spinDirFactor = 1 -- negative for clockwise, positive for counter-clockwise if m.actionState == 1 then spinDirFactor = -1 end set_mario_animation(m, MARIO_ANIM_TWIRL) if (m.input & INPUT_B_PRESSED) ~= 0 then mario_set_forward_vel(m, 10.0) m.vel.y = 35 set_mario_action(m, ACT_DIVE, 0) end local stepResult = perform_air_step(m, 0) if stepResult == AIR_STEP_LANDED then if should_get_stuck_in_ground(m) ~= 0 then queue_rumble_data_mario(m, 5, 80) play_sound(CHAR_SOUND_OOOF2, m.marioObj.header.gfx.cameraToObject) m.particleFlags = m.particleFlags | PARTICLE_MIST_CIRCLE set_mario_action(m, ACT_BUTT_STUCK_IN_GROUND, 0) else play_mario_heavy_landing_sound(m, SOUND_ACTION_TERRAIN_HEAVY_LANDING) if check_fall_damage(m, ACT_HARD_BACKWARD_GROUND_KB) == 0 then m.particleFlags = m.particleFlags | PARTICLE_MIST_CIRCLE | PARTICLE_HORIZONTAL_STAR set_mario_action(m, ACT_SPIN_POUND_LAND, 0) end end set_camera_shake_from_hit(SHAKE_GROUND_POUND) elseif stepResult == AIR_STEP_HIT_WALL then mario_set_forward_vel(m, -16.0) if m.vel.y > 0.0 then m.vel.y = 0.0 end m.particleFlags = m.particleFlags | PARTICLE_VERTICAL_STAR set_mario_action(m, ACT_BACKWARD_AIR_KB, 0) end -- set facing direction -- not part of original Extended Moveset local yawDiff = m.faceAngle.y - m.intendedYaw e.rotAngle = limit_angle(e.rotAngle + yawDiff) m.faceAngle.y = m.intendedYaw e.rotAngle = e.rotAngle + 0x3053 if e.rotAngle > 0x10000 then e.rotAngle = e.rotAngle - 0x10000 end if e.rotAngle < -0x10000 then e.rotAngle = e.rotAngle + 0x10000 end m.marioObj.header.gfx.angle.y = limit_angle(m.marioObj.header.gfx.angle.y + e.rotAngle * spinDirFactor) m.actionTimer = m.actionTimer + 1 return 0 end function act_spin_pound_land(m) m.actionState = 1 if m.actionTimer <= 8 then if (m.input & INPUT_UNKNOWN_10) ~= 0 then return drop_and_set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0) end if (m.input & INPUT_OFF_FLOOR) ~= 0 then return set_mario_action(m, ACT_FREEFALL, 0) end if (m.input & INPUT_ABOVE_SLIDE) ~= 0 then return set_mario_action(m, ACT_BUTT_SLIDE, 0) end if (m.input & INPUT_A_PRESSED) ~= 0 then return set_jumping_action(m, ACT_GROUND_POUND_JUMP, 0) end if (m.controller.buttonPressed & X_BUTTON) ~= 0 then mario_set_forward_vel(m, 60) play_sound(SOUND_ACTION_SPIN, m.marioObj.header.gfx.cameraToObject) return set_mario_action(m, ACT_ROLL, 0) end stationary_ground_step(m) set_mario_animation(m, MARIO_ANIM_LAND_FROM_DOUBLE_JUMP) else if (m.input & INPUT_UNKNOWN_10) ~= 0 then return set_mario_action(m, ACT_SHOCKWAVE_BOUNCE, 0) end if (m.input & (INPUT_NONZERO_ANALOG | INPUT_A_PRESSED | INPUT_OFF_FLOOR | INPUT_ABOVE_SLIDE)) ~= 0 then return check_common_action_exits(m) end stopping_step(m, MARIO_ANIM_LAND_FROM_DOUBLE_JUMP, ACT_IDLE) end m.actionTimer = m.actionTimer + 1 return 0 end ---------------- -- wall slide -- ---------------- function act_wall_slide(m) local e = gMarioStateExtras[m.playerIndex] e.savedWallSlideHeight = m.pos.y e.savedWallSlide = true if (m.input & INPUT_A_PRESSED) ~= 0 then m.vel.y = 52.0 -- m.faceAngle.y = limit_angle(m.faceAngle.y + 0x8000) return set_mario_action(m, ACT_WALL_KICK_AIR, 0) end -- attempt to stick to the wall a bit. if it's 0, sometimes you'll get kicked off of slightly sloped walls mario_set_forward_vel(m, -1.0) m.particleFlags = m.particleFlags | PARTICLE_DUST play_sound(SOUND_MOVING_TERRAIN_SLIDE + m.terrainSoundAddend, m.marioObj.header.gfx.cameraToObject) set_mario_animation(m, MARIO_ANIM_START_WALLKICK) if perform_air_step(m, 0) == AIR_STEP_LANDED then mario_set_forward_vel(m, 0.0) if check_fall_damage_or_get_stuck(m, ACT_HARD_BACKWARD_GROUND_KB) == 0 then return set_mario_action(m, ACT_FREEFALL_LAND, 0) end end m.actionTimer = m.actionTimer + 1 if m.wall == nil and m.actionTimer > 2 then mario_set_forward_vel(m, 0.0) return set_mario_action(m, ACT_FREEFALL, 0) end return 0 end function act_wall_slide_gravity(m) m.vel.y = m.vel.y - 2 if m.vel.y < -15 then m.vel.y = -15 end end function act_air_hit_wall(m) if m.heldObj ~= 0 then mario_drop_held_object(m) end m.actionTimer = m.actionTimer + 1 if m.actionTimer <= 1 and (m.input & INPUT_A_PRESSED) ~= 0 then m.vel.y = 52.0 m.faceAngle.y = limit_angle(m.faceAngle.y + 0x8000) return set_mario_action(m, ACT_WALL_KICK_AIR, 0) elseif m.forwardVel >= 38.0 then m.wallKickTimer = 5 if m.vel.y > 0.0 then m.vel.y = 0.0 end m.particleFlags = m.particleFlags | PARTICLE_VERTICAL_STAR return set_mario_action(m, ACT_BACKWARD_AIR_KB, 0) else m.faceAngle.y = limit_angle(m.faceAngle.y + 0x8000) return set_mario_action(m, ACT_WALL_SLIDE, 0) end --! Missing return statement (in original C code). The returned value is the result of the call -- to set_mario_animation. In practice, this value is nonzero. -- This results in this action "cancelling" into itself. It is supposed to -- execute three times, each on a separate frame, but instead it executes -- three times on the same frame. -- This results in firsties only being possible for a single frame, instead -- of three. return set_mario_animation(m, MARIO_ANIM_START_WALLKICK) end ------------------------ -- water ground pound -- ------------------------ function act_water_ground_pound(m) local GROUND_POUND_STROKE_SPEED = 27 local GROUND_POUND_TIMER = 30 local stepResult = 0 if m.actionTimer == 0 then -- coming into action from normal ground pound if m.actionArg == 1 then -- copied from water plunge code play_sound(SOUND_ACTION_UNKNOWN430, m.marioObj.header.gfx.cameraToObject) if m.peakHeight - m.pos.y > 1150.0 then play_sound(CHAR_SOUND_HAHA_2, m.marioObj.header.gfx.cameraToObject) end m.particleFlags = m.particleFlags | PARTICLE_WATER_SPLASH if (m.prevAction & ACT_FLAG_AIR) ~= 0 then queue_rumble_data_mario(m, 5, 80) end end m.actionState = m.actionArg elseif m.actionTimer == 1 then play_sound(SOUND_ACTION_SWIM, m.marioObj.header.gfx.cameraToObject) end if m.actionState == 0 then if m.actionTimer == 0 then m.vel.y = 0.0 mario_set_forward_vel(m, 0.0) end m.faceAngle.x = 0 m.faceAngle.z = 0 set_mario_animation(m, MARIO_ANIM_START_GROUND_POUND) if m.actionTimer == 0 then play_sound(SOUND_ACTION_SPIN, m.marioObj.header.gfx.cameraToObject) end m.actionTimer = m.actionTimer + 1 if (m.actionTimer >= m.marioObj.header.gfx.animInfo.curAnim.loopEnd + 4) then -- play_sound(CHAR_SOUND_GROUND_POUND_WAH, m.marioObj.header.gfx.cameraToObject) play_sound(SOUND_ACTION_SWIM_FAST, m.marioObj.header.gfx.cameraToObject) m.vel.y = -45.0 m.actionState = 1 end if (m.input & INPUT_A_PRESSED) ~= 0 then mario_set_forward_vel(m, GROUND_POUND_STROKE_SPEED) m.vel.y = 0 return set_mario_action(m, ACT_WATER_GROUND_POUND_STROKE, 0) end -- make current apply stepResult = perform_water_step(m) else set_mario_animation(m, MARIO_ANIM_GROUND_POUND) m.particleFlags = m.particleFlags | PARTICLE_PLUNGE_BUBBLE local nextPos = {} nextPos.x = m.pos.x + m.vel.x nextPos.y = m.pos.y + m.vel.y nextPos.z = m.pos.z + m.vel.z -- call this one to make current NOT apply stepResult = perform_water_full_step(m, nextPos) vec3f_copy(m.marioObj.header.gfx.pos, m.pos) vec3s_set(m.marioObj.header.gfx.angle, -m.faceAngle.x, m.faceAngle.y, m.faceAngle.z) if stepResult == WATER_STEP_HIT_FLOOR then play_mario_heavy_landing_sound(m, SOUND_ACTION_TERRAIN_HEAVY_LANDING) m.particleFlags = m.particleFlags | PARTICLE_MIST_CIRCLE | PARTICLE_HORIZONTAL_STAR set_mario_action(m, ACT_WATER_GROUND_POUND_LAND, 0) set_camera_shake_from_hit(SHAKE_GROUND_POUND) else if (m.input & INPUT_A_PRESSED) ~= 0 then mario_set_forward_vel(m, GROUND_POUND_STROKE_SPEED) m.vel.y = 0 return set_mario_action(m, ACT_WATER_GROUND_POUND_STROKE, 0) end m.vel.y = approach_f32(m.vel.y, 0, 2.0, 2.0) mario_set_forward_vel(m, 0.0) if m.actionTimer >= GROUND_POUND_TIMER or m.vel.y >= 0.0 then set_mario_action(m, ACT_WATER_ACTION_END, 0) end end m.actionTimer = m.actionTimer + 1 end return 0 end function act_water_ground_pound_land(m) local GROUND_POUND_JUMP_VEL = 40.0 m.actionState = 1 if (m.input & INPUT_OFF_FLOOR) ~= 0 then return set_mario_action(m, ACT_WATER_IDLE, 0) end if (m.input & INPUT_A_PRESSED) ~= 0 then m.vel.y = GROUND_POUND_JUMP_VEL play_sound(SOUND_ACTION_SWIM_FAST, m.marioObj.header.gfx.cameraToObject) return set_mario_action(m, ACT_WATER_GROUND_POUND_JUMP, 0) end m.vel.y = 0.0 m.pos.y = m.floorHeight mario_set_forward_vel(m, 0.0) vec3f_copy(m.marioObj.header.gfx.pos, m.pos) vec3s_set(m.marioObj.header.gfx.angle, 0, m.faceAngle.y, 0) set_mario_animation(m, MARIO_ANIM_GROUND_POUND_LANDING) if is_anim_at_end(m) ~= 0 then return set_mario_action(m, ACT_SWIMMING_END, 0) end perform_water_step(m) return 0 end function act_water_ground_pound_stroke(m) local GROUND_POUND_STROKE_TIMER = 20 local GROUND_POUND_STROKE_DECAY = 0.3 local stepResult = 0 set_mario_animation(m, MARIO_ANIM_SWIM_PART1) if m.actionTimer == 0 then play_sound(SOUND_ACTION_SWIM_FAST, m.marioObj.header.gfx.cameraToObject) end stepResult = perform_water_step(m) if stepResult == WATER_STEP_HIT_WALL then return set_mario_action(m, ACT_BACKWARD_WATER_KB, 0) end if m.actionTimer >= GROUND_POUND_STROKE_TIMER then if (m.input & INPUT_A_DOWN) ~= 0 then return set_mario_action(m, ACT_FLUTTER_KICK, 0) else return set_mario_action(m, ACT_SWIMMING_END, 0) end end m.actionTimer = m.actionTimer + 1 mario_set_forward_vel(m, approach_f32(m.forwardVel, 0.0, GROUND_POUND_STROKE_DECAY, GROUND_POUND_STROKE_DECAY)) float_surface_gfx(m) set_swimming_at_surface_particles(m, PARTICLE_WAVE_TRAIL) return 0 end function act_water_ground_pound_jump(m) local e = gMarioStateExtras[m.playerIndex] local GROUND_POUND_JUMP_TIMER = 20 local GROUND_POUND_JUMP_DECAY = 1.4 -- set_mario_animation(m, MARIO_ANIM_SWIM_PART1) set_mario_animation(m, MARIO_ANIM_SINGLE_JUMP) m.particleFlags = m.particleFlags | PARTICLE_PLUNGE_BUBBLE if m.actionTimer == 0 then e.rotAngle = 0 end local step = {} vec3f_copy(step, m.vel) apply_water_current(m, step) local nextPos = {} nextPos.x = m.pos.x + step.x nextPos.y = m.pos.y + step.y nextPos.z = m.pos.z + step.z local stepResult = perform_water_full_step(m, nextPos) vec3f_copy(m.marioObj.header.gfx.pos, m.pos) vec3s_set(m.marioObj.header.gfx.angle, -m.faceAngle.x, m.faceAngle.y, m.faceAngle.z) if m.pos.y > m.waterLevel - 80 then return set_mario_action(m, ACT_WATER_JUMP, 0) end if m.actionTimer >= GROUND_POUND_JUMP_TIMER then mario_set_forward_vel(m, m.vel.y) -- normal swim routines will use forwardVel to calculate y speed m.faceAngle.x = 0x3EFF if (m.input & INPUT_A_DOWN) ~= 0 then return set_mario_action(m, ACT_FLUTTER_KICK, 0) else return set_mario_action(m, ACT_SWIMMING_END, 0) end end m.actionTimer = m.actionTimer + 1 mario_set_forward_vel(m, 0.0) m.vel.y = approach_f32(m.vel.y, 0.0, GROUND_POUND_JUMP_DECAY, GROUND_POUND_JUMP_DECAY) -- m.faceAngle.x = 0x3EFF float_surface_gfx(m) set_swimming_at_surface_particles(m, PARTICLE_WAVE_TRAIL) e.rotAngle = e.rotAngle + (0x10000*1.0 - e.rotAngle) / 5.0 m.marioObj.header.gfx.angle.y = limit_angle(m.marioObj.header.gfx.angle.y - e.rotAngle) return 0 end ------------------- -- ledge parkour -- ------------------- function act_ledge_parkour(m) set_mario_animation(m, MARIO_ANIM_SLIDEFLIP) local animFrame = m.marioObj.header.gfx.animInfo.animFrame if m.actionTimer == 0 then play_sound(CHAR_SOUND_HAHA_2, m.marioObj.header.gfx.cameraToObject) elseif m.actionTimer == 1 then play_sound(SOUND_ACTION_SIDE_FLIP_UNK, m.marioObj.header.gfx.cameraToObject) end update_air_without_turn(m) local step = perform_air_step(m, AIR_STEP_CHECK_LEDGE_GRAB) if step == AIR_STEP_NONE then -- play the side flip animation at double speed for a portion of it if animFrame < 15 then animFrame = animFrame + 2 elseif animFrame > 23 then animFrame = 23 else animFrame = animFrame + 1 end set_anim_to_frame(m, animFrame) m.marioObj.header.gfx.angle.y = m.marioObj.header.gfx.angle.y + 0x8000 elseif step == AIR_STEP_LANDED then m.marioObj.header.gfx.angle.y = m.marioObj.header.gfx.angle.y + 0x8000 set_mario_action(m, ACT_FREEFALL_LAND_STOP, 0) play_mario_landing_sound(m, SOUND_ACTION_TERRAIN_LANDING) elseif step == AIR_STEP_HIT_WALL then m.marioObj.header.gfx.angle.y = m.marioObj.header.gfx.angle.y + 0x8000 mario_set_forward_vel(m, 0.0) elseif step == AIR_STEP_HIT_LAVA_WALL then m.marioObj.header.gfx.angle.y = m.marioObj.header.gfx.angle.y + 0x8000 lava_boost_on_wall(m) end m.actionTimer = m.actionTimer + 1 return 0 end function act_ground_pound_jump(m) local e = gMarioStateExtras[m.playerIndex] if check_kick_or_dive_in_air(m) ~= 0 then m.marioObj.header.gfx.angle.y = m.marioObj.header.gfx.angle.y + e.rotAngle return 1 end if (m.input & INPUT_Z_PRESSED) ~= 0 then m.marioObj.header.gfx.angle.y = m.marioObj.header.gfx.angle.y + e.rotAngle return set_mario_action(m, ACT_GROUND_POUND, 0) end if e.spinInput ~= 0 then return set_mario_action(m, ACT_SPIN_JUMP, 1) end if m.actionTimer == 0 then e.rotAngle = 0 elseif m.actionTimer == 1 then play_sound(SOUND_ACTION_SPIN, m.marioObj.header.gfx.cameraToObject) end play_mario_sound(m, SOUND_ACTION_TERRAIN_JUMP, CHAR_SOUND_YAHOO) common_air_action_step(m, ACT_JUMP_LAND, MARIO_ANIM_SINGLE_JUMP, AIR_STEP_CHECK_LEDGE_GRAB | AIR_STEP_CHECK_HANG) e.rotAngle = e.rotAngle + (0x10000*1.0 - e.rotAngle) / 5.0 m.marioObj.header.gfx.angle.y = m.marioObj.header.gfx.angle.y - e.rotAngle m.actionTimer = m.actionTimer + 1 return 0 end ------------------------------------- -- dive slide patched for dive hop -- ------------------------------------- function act_dive_slide(m) if (m.input & INPUT_ABOVE_SLIDE) == 0 and (m.input & INPUT_A_PRESSED) ~= 0 then queue_rumble_data_mario(m, 5, 80) if m.forwardVel > 0 then return set_mario_action(m, ACT_FORWARD_ROLLOUT, 0) else return set_mario_action(m, ACT_BACKWARD_ROLLOUT, 0) end end if (m.input & INPUT_ABOVE_SLIDE) == 0 then if (m.input & INPUT_B_PRESSED) ~= 0 then -- dive hop m.vel.y = 21.0 return set_mario_action(m, ACT_DIVE, 1) end end play_mario_landing_sound_once(m, SOUND_ACTION_TERRAIN_BODY_HIT_GROUND) --! If the dive slide ends on the same frame that we pick up on object, -- Mario will not be in the dive slide action for the call to -- mario_check_object_grab, and so will end up in the regular picking action, -- rather than the picking up after dive action. if update_sliding(m, 8.0) ~= 0 and is_anim_at_end(m) ~= 0 then mario_set_forward_vel(m, 0.0) set_mario_action(m, ACT_STOMACH_SLIDE_STOP, 0) end if mario_check_object_grab(m) ~= 0 then mario_grab_used_object(m) if m.heldObj ~= 0 then m.marioBodyState.grabPos = GRAB_POS_LIGHT_OBJ end return true end common_slide_action(m, ACT_STOMACH_SLIDE_STOP, ACT_FREEFALL, MARIO_ANIM_DIVE) return false end ------------------------------------------------------- -- Patched actions using update_walking_speed action -- -- for Tight Controls and modfied speed caps -- ------------------------------------------------------- function update_walking_speed_extended(m) local maxTargetSpeed = 0 local targetSpeed = 0 local firmSpeedCap = 0 local hardSpeedCap = 105.0 if m.prevAction == ACT_ROLL then firmSpeedCap = 60.0 else firmSpeedCap = 48.0 end if m.floor ~= 0 and m.floor.type == SURFACE_SLOW then maxTargetSpeed = 24.0 else maxTargetSpeed = 32.0 end if m.intendedMag < maxTargetSpeed then targetSpeed = m.intendedMag else targetSpeed = maxTargetSpeed end if m.quicksandDepth > 10.0 then targetSpeed = targetSpeed * (6.25 / m.quicksandDepth) end if m.forwardVel <= 8.0 then m.forwardVel = math.min(m.intendedMag, 8.0) -- Same fix as Melee dashback (by Kaze) end -- instead of a hard walk speed cap, going over this new firm speed cap makes you slow down to it twice as fast local decayFactor = 0 if m.forwardVel > firmSpeedCap then decayFactor = 2.0 else decayFactor = 1.0 end if m.forwardVel <= 0.0 then m.forwardVel = m.forwardVel + 1.1 elseif m.forwardVel <= targetSpeed then m.forwardVel = m.forwardVel + (1.1 - m.forwardVel / 43.0) elseif m.floor ~= 0 and m.floor.normal.y >= 0.95 then m.forwardVel = m.forwardVel - decayFactor else -- reintroduce the old hardcap for the weird slopes where you kind of just maintain your speed if (m.forwardVel > firmSpeedCap) then m.forwardVel = firmSpeedCap; end end if m.forwardVel > hardSpeedCap then m.forwardVel = hardSpeedCap end if analog_stick_held_back(m) ~= 0 then m.faceAngle.y = m.intendedYaw; if m.forwardVel < 0 then mario_set_forward_vel(m, -m.forwardVel); end else m.faceAngle.y = m.intendedYaw - approach_s32(limit_angle(m.intendedYaw - m.faceAngle.y), 0, 0xC00, 0xC00); end apply_slope_accel(m) end function act_walking(m) local startPos = m.pos local startYaw = m.faceAngle.y mario_drop_held_object(m) if should_begin_sliding(m) ~= 0 then return set_mario_action(m, ACT_BEGIN_SLIDING, 0) end if (m.input & INPUT_FIRST_PERSON) ~= 0 then return begin_braking_action(m) end if (m.input & INPUT_A_PRESSED) ~= 0 then return set_jump_from_landing(m) end if check_ground_dive_or_punch(m) ~= 0 then return true end if (m.input & INPUT_ZERO_MOVEMENT) ~= 0 then return begin_braking_action(m) end if analog_stick_held_back(m) ~= 0 and m.forwardVel >= 12.0 then return set_mario_action(m, ACT_TURNING_AROUND, 0) end if (m.input & INPUT_Z_PRESSED) ~= 0 then return set_mario_action(m, ACT_CROUCH_SLIDE, 0) end m.actionState = 0 vec3f_copy(startPos, m.pos) update_walking_speed_extended(m) local stepResult = perform_ground_step(m) if stepResult == GROUND_STEP_LEFT_GROUND then set_mario_action(m, ACT_FREEFALL, 0) set_mario_animation(m, MARIO_ANIM_GENERAL_FALL) elseif stepResult == GROUND_STEP_NONE then anim_and_audio_for_walk(m) if (m.intendedMag - m.forwardVel > 16.0) then m.particleFlags = m.particleFlags | PARTICLE_DUST end elseif stepResult == GROUND_STEP_HIT_WALL then push_or_sidle_wall(m, startPos) m.actionTimer = 0 end check_ledge_climb_down(m) tilt_body_walking(m, startYaw) return false end function act_hold_walking(m) if m.heldObj.behavior == bhvJumpingBox then return set_mario_action(m, ACT_CRAZY_BOX_BOUNCE, 0) end if (m.marioObj.oInteractStatus & INT_STATUS_MARIO_DROP_OBJECT) ~= 0 then return drop_and_set_mario_action(m, ACT_WALKING, 0) end if should_begin_sliding(m) ~= 0 then return set_mario_action(m, ACT_HOLD_BEGIN_SLIDING, 0) end if (m.input & INPUT_B_PRESSED) ~= 0 then return set_mario_action(m, ACT_THROWING, 0) end if (m.input & INPUT_A_PRESSED) ~= 0 then return set_jumping_action(m, ACT_HOLD_JUMP, 0) end if (m.input & INPUT_ZERO_MOVEMENT) ~= 0 then return set_mario_action(m, ACT_HOLD_DECELERATING, 0) end if (m.input & INPUT_Z_PRESSED) ~= 0 then return drop_and_set_mario_action(m, ACT_CROUCH_SLIDE, 0) end m.intendedMag = m.intendedMag * 0.4 update_walking_speed_extended(m) local stepResult = perform_ground_step(m) if stepResult == GROUND_STEP_LEFT_GROUND then set_mario_action(m, ACT_HOLD_FREEFALL, 0) elseif stepResult == GROUND_STEP_HIT_WALL then if m.forwardVel > 16.0 then mario_set_forward_vel(m, 16.0) end end anim_and_audio_for_hold_walk(m) if 0.4 * m.intendedMag - m.forwardVel > 10.0 then m.particleFlags = m.particleFlags | PARTICLE_DUST end return false end function act_hold_heavy_walking(m) if (m.input & INPUT_B_PRESSED) ~= 0 then return set_mario_action(m, ACT_HEAVY_THROW, 0) end if should_begin_sliding(m) ~= 0 then return drop_and_set_mario_action(m, ACT_BEGIN_SLIDING, 0) end if (m.input & INPUT_ZERO_MOVEMENT) ~= 0 then return set_mario_action(m, ACT_HOLD_HEAVY_IDLE, 0) end m.intendedMag = m.intendedMag * 0.1 update_walking_speed_extended(m) local stepResult = perform_ground_step(m) if stepResult == GROUND_STEP_LEFT_GROUND then drop_and_set_mario_action(m, ACT_FREEFALL, 0) elseif stepResult == GROUND_STEP_HIT_WALL then if (m.forwardVel > 10.0) then mario_set_forward_vel(m, 10.0) end end anim_and_audio_for_heavy_walk(m) return false end function act_finish_turning_around(m) if (m.input & INPUT_ABOVE_SLIDE) ~= 0 then return set_mario_action(m, ACT_BEGIN_SLIDING, 0) end if (m.input & INPUT_A_PRESSED) ~= 0 then return set_jumping_action(m, ACT_SIDE_FLIP, 0) end update_walking_speed_extended(m) set_mario_animation(m, MARIO_ANIM_TURNING_PART2) if perform_ground_step(m) == GROUND_STEP_LEFT_GROUND then set_mario_action(m, ACT_FREEFALL, 0) end if is_anim_at_end(m) ~= 0 then set_mario_action(m, ACT_WALKING, 0) end m.marioObj.header.gfx.angle.y = limit_angle(m.marioObj.header.gfx.angle.y + 0x8000) return false end function act_crawling(m) if should_begin_sliding(m) ~= 0 then return set_mario_action(m, ACT_BEGIN_SLIDING, 0) end if (m.input & INPUT_FIRST_PERSON) ~= 0 then return set_mario_action(m, ACT_STOP_CRAWLING, 0) end if (m.input & INPUT_A_PRESSED) ~= 0 then return set_jumping_action(m, ACT_JUMP, 0) end if check_ground_dive_or_punch(m) ~= 0 then return true end if (m.input & INPUT_ZERO_MOVEMENT) ~= 0 then return set_mario_action(m, ACT_STOP_CRAWLING, 0) end if (m.input & INPUT_Z_DOWN) == 0 then return set_mario_action(m, ACT_STOP_CRAWLING, 0) end m.intendedMag = m.intendedMag * 0.1 update_walking_speed_extended(m) local stepResult = perform_ground_step(m) if stepResult == GROUND_STEP_LEFT_GROUND then set_mario_action(m, ACT_FREEFALL, 0) elseif stepResult == GROUND_STEP_HIT_WALL then if m.forwardVel > 10.0 then mario_set_forward_vel(m, 10.0) end --! Possibly unintended missing break align_with_floor(m) elseif stepResult == GROUND_STEP_NONE then align_with_floor(m) end local val04 = (m.intendedMag * 2.0 * 0x10000) set_mario_anim_with_accel(m, MARIO_ANIM_CRAWLING, val04) play_step_sound(m, 26, 79) return false end --------------------------------------------------------- function mario_on_set_action(m) local e = gMarioStateExtras[m.playerIndex] if (m.action & ACT_FLAG_MOVING) ~= 0 then e.savedWallSlide = false end if e.spinInput ~= 0 and (m.input & INPUT_ABOVE_SLIDE) == 0 then if m.action == ACT_JUMP or m.action == ACT_DOUBLE_JUMP or m.action == ACT_TRIPLE_JUMP or m.action == ACT_SPECIAL_TRIPLE_JUMP or m.action == ACT_SIDE_FLIP or m.action == ACT_BACKFLIP then set_mario_action(m, ACT_SPIN_JUMP, 1) m.vel.y = 65.0 m.faceAngle.y = m.intendedYaw end end if m.action == ACT_GROUND_POUND_JUMP then m.vel.y = 65.0 elseif m.action == ACT_WATER_PLUNGE and m.prevAction == ACT_GROUND_POUND then return set_mario_action(m, ACT_WATER_GROUND_POUND, 1) elseif m.action == ACT_WALL_SLIDE then m.vel.y = 0.0 elseif m.action == ACT_GROUND_POUND and m.prevAction == ACT_SIDE_FLIP then -- correct animation m.marioObj.header.gfx.angle.y = limit_angle(m.marioObj.header.gfx.angle.y - 0x8000) elseif m.action == ACT_LEDGE_GRAB then e.rotAngle = m.forwardVel end end function before_mario_update(m) local e = gMarioStateExtras[m.playerIndex] -- revert fake saved action if e.fakeSaved == true then if m.action == e.fakeWroteAction and m.prevAction == e.fakeSavedPrevAction and m.actionTimer == e.fakeSavedActionTimer then m.action = e.fakeSavedAction end e.fakeSaved = false end end function after_mario_update(m) local e = gMarioStateExtras[m.playerIndex] -- pretend *_POUND_LAND is ACT_GROUND_POUND_LAND so switches work correctly if m.action == ACT_SPIN_POUND_LAND or m.action == ACT_WATER_GROUND_POUND_LAND then e.fakeSavedAction = m.action e.fakeSavedPrevAction = m.prevAction e.fakeSavedActionTimer = m.actionTimer m.action = ACT_GROUND_POUND_LAND e.fakeWroteAction = m.action e.fakeSaved = true end end function mario_update(m) local e = gMarioStateExtras[m.playerIndex] mario_update_spin_input(m) update_roll(m) -- dive out of ACT_GROUND_POUND if m.action == ACT_GROUND_POUND and (m.input & INPUT_B_PRESSED) ~= 0 then mario_set_forward_vel(m, 10.0) m.vel.y = 35.0 set_mario_action(m, ACT_DIVE, 0) end -- spin if (m.action == ACT_JUMP or m.action == ACT_WALL_KICK_AIR or m.action == ACT_DOUBLE_JUMP or m.action == ACT_BACKFLIP or m.action == ACT_SIDE_FLIP) and e.spinInput ~= 0 then set_mario_action(m, ACT_SPIN_JUMP, 1) e.spinInput = 0 end -- twirl pound if m.action == ACT_TWIRLING and (m.input & INPUT_Z_PRESSED) ~= 0 then set_mario_action(m, ACT_SPIN_POUND, 0) end -- ground pound jump if m.action == ACT_GROUND_POUND_LAND and (m.input & INPUT_A_PRESSED) ~= 0 then set_mario_action(m, ACT_GROUND_POUND_JUMP, 0) end -- water ground pound if (m.input & INPUT_Z_PRESSED) ~= 0 then if m.action == ACT_WATER_IDLE or m.action == ACT_WATER_ACTION_END or m.action == ACT_BREASTSTROKE or m.action == ACT_SWIMMING_END or m.action == ACT_FLUTTER_KICK then set_mario_action(m, ACT_WATER_GROUND_POUND, 0) end end -- maintain spinning from water ground pound jump anim if m.action == ACT_WATER_JUMP and m.prevAction == ACT_WATER_GROUND_POUND_JUMP then e.rotAngle = e.rotAngle + (0x10000*1.0 - e.rotAngle) / 5.0 m.marioObj.header.gfx.angle.y = limit_angle(m.marioObj.header.gfx.angle.y - e.rotAngle) end -- edge parkour if m.action == ACT_LEDGE_GRAB and m.actionTimer < 4 and (m.input & INPUT_B_PRESSED) ~= 0 then local hasSpaceForMario = (m.ceilHeight - m.floorHeight >= 160.0) if hasSpaceForMario and (e.rotAngle >= 31.0 or m.forwardVel >= 31.0) then mario_set_forward_vel(m, e.rotAngle + 5.0) m.vel.y = 25.0 queue_rumble_data_mario(m, 5, 80) set_mario_action(m, ACT_LEDGE_PARKOUR, 0) end end -- save last pos e.lastPos.x = m.pos.x e.lastPos.y = m.pos.y e.lastPos.z = m.pos.z after_mario_update(m) end ----------- -- hooks -- ----------- hook_event(HOOK_BEFORE_MARIO_UPDATE, before_mario_update) hook_event(HOOK_MARIO_UPDATE, mario_update) hook_event(HOOK_ON_SET_MARIO_ACTION, mario_on_set_action) hook_mario_action(ACT_ROLL, { every_frame = act_roll }) hook_mario_action(ACT_ROLL_AIR, { every_frame = act_roll_air }) hook_mario_action(ACT_SPIN_JUMP, { every_frame = act_spin_jump, gravity = act_spin_jump_gravity }) hook_mario_action(ACT_SPIN_POUND, { every_frame = act_spin_pound }) hook_mario_action(ACT_SPIN_POUND_LAND, { every_frame = act_spin_pound_land }) hook_mario_action(ACT_GROUND_POUND_JUMP, { every_frame = act_ground_pound_jump }) hook_mario_action(ACT_WALL_SLIDE, { every_frame = act_wall_slide, gravity = act_wall_slide_gravity }) hook_mario_action(ACT_WATER_GROUND_POUND, { every_frame = act_water_ground_pound }) hook_mario_action(ACT_WATER_GROUND_POUND_LAND, { every_frame = act_water_ground_pound_land }) hook_mario_action(ACT_WATER_GROUND_POUND_STROKE, { every_frame = act_water_ground_pound_stroke }) hook_mario_action(ACT_WATER_GROUND_POUND_JUMP, { every_frame = act_water_ground_pound_jump }) hook_mario_action(ACT_LEDGE_PARKOUR, { every_frame = act_ledge_parkour }) hook_mario_action(ACT_DIVE_SLIDE, { every_frame = act_dive_slide }) hook_mario_action(ACT_WALKING, { every_frame = act_walking }) hook_mario_action(ACT_HOLD_WALKING, { every_frame = act_hold_walking }) hook_mario_action(ACT_HOLD_HEAVY_WALKING, { every_frame = act_hold_heavy_walking }) hook_mario_action(ACT_FINISH_TURNING_AROUND, { every_frame = act_finish_turning_around }) hook_mario_action(ACT_CRAWLING, { every_frame = act_crawling }) hook_mario_action(ACT_AIR_HIT_WALL, { every_frame = act_air_hit_wall })