-- name: Spiral Mario
-- description: Spiral Mario Can Spin!
ACT_SPIRALMARIO_SPIRAL = allocate_mario_action(ACT_FLAG_AIR)
ACT_SPIRALMARIO_FLING = allocate_mario_action(ACT_FLAG_AIR)
gStateExtras = {}
local function lerp(a,b,i)
return a+((b-a)*i)
end
local function invlerp(a,b,x)
return (x-a)/(b-a)
end
local function eulerToForDir(euler)
local x =0
local z =0
if(euler<180) then
z = invlerp(90,0,euler)
if(euler<90) then
x = invlerp(0,90,euler)
else
x = invlerp(180,90,euler)
end
else
z = invlerp(270,360,euler)
if(euler>=270) then
x = invlerp(360,270,euler)
else
x = invlerp(180,270,euler)
end
x=x*-1
end
local ret = {}
vec3f_set(ret,x,0,z)
vec3f_normalize(ret)
return ret
end
local function intAngleToEuler(intAng)
local angI = invlerp(-32768,32767,intAng)
return lerp(0,360,angI)
end
local function initExtrasByIndex(i)
gStateExtras[i] = {}
local e = gStateExtras[i]
e.startPos = {}
vec3f_set(e.startPos,0,0,0)
e.spiralTime_cur = 0
e.facingEulerY = 0
e.flingVec = {}
e.spiralOvalProgressTicks = 0
vec3f_set(e.flingVec,0,0,0)
return gStateExtras[i]
end
local function initExtrasByPlayer(m)
local player = initExtrasByIndex(m.playerIndex)
player.facingEulerY = intAngleToEuler(m.faceAngle.y)
return player
end
local function mario_update(m)
if m.action == ACT_GROUND_POUND and m.controller.buttonPressed & A_BUTTON ~=0 then
local e = initExtrasByPlayer(m)
vec3f_copy(e.startPos,m.pos)
set_mario_action(m,ACT_SPIRALMARIO_SPIRAL,0)
end
end
local function act_spiralmario_common_airstep(m,prevToCurVec)
vec3f_copy(m.vel,prevToCurVec)
local stepResult = perform_air_step(m,0)
-- vec3f are a class and therefore passed by reference, so changing these values DOES
-- make a difference in the method that called this one
vec3f_copy(prevToCurVec,m.vel)
-- recreation of only what i need from common_air_action_step from https://github.com/n64decomp/sm64/blob/master/src/game/mario_actions_airborne.c
-- without having to rely on forwardVel since IDK what value it should be at this time
if(stepResult == AIR_STEP_HIT_WALL) then
set_mario_action(m,ACT_GROUND_BONK,0)
elseif (stepResult== AIR_STEP_HIT_LAVA_WALL) then
lava_boost_on_wall(m)
elseif (stepResult == AIR_STEP_LANDED) then
set_mario_action(m,ACT_JUMP_LAND_STOP,0)
end
end
local function act_spiralmario_common_setup(m)
set_mario_animation(m,MARIO_ANIM_FORWARD_SPINNING)
local e = gStateExtras[m.playerIndex]
return e
end
local function act_spiralmario_fling(m)
local e = act_spiralmario_common_setup(m)
act_spiralmario_common_airstep(m,e.flingVec)
end
local function act_spiralmario_spiral(m)
local e = act_spiralmario_common_setup(m)
local spiralTime_cur_int = math.floor(e.spiralTime_cur)
local spiralTime_max = 17
local spiralExag_max = 275
local timeStep = 0.45
local spiralSndInverseRate = 3
local spiralOvalMultMin = 1
local spiralOvalMultMax = 1.3
if(spiralTime_cur_int % math.max(math.floor(spiralSndInverseRate),1) == 0) then
play_sound(SOUND_ACTION_THROW,m.marioObj.header.gfx.cameraToObject)
end
local spiralExag_cur = lerp(0,spiralExag_max,(1/spiralTime_max)*e.spiralTime_cur)
local dir_for = {}
vec3f_copy(dir_for,eulerToForDir(e.facingEulerY))
local dir_up = {}
vec3f_set(dir_up,0,1,0)
vec3f_normalize(dir_up)
local finalPos = {}
vec3f_copy(finalPos,e.startPos)
vec3f_mul(dir_for,(math.sin(e.spiralTime_cur) * spiralExag_cur))
vec3f_mul(dir_up,(math.cos(e.spiralTime_cur) * spiralExag_cur * lerp(spiralOvalMultMin,spiralOvalMultMax,invlerp(0,spiralTime_max,e.spiralOvalProgressTicks))))
vec3f_add(finalPos,dir_for)
vec3f_add(finalPos,dir_up)
local prevPos = {}
vec3f_copy(prevPos,m.pos)
local moveVec = {}
vec3f_copy(moveVec,finalPos)
vec3f_sub(moveVec,prevPos)
act_spiralmario_common_airstep(m,moveVec)
e.spiralTime_cur = e.spiralTime_cur + timeStep
if(m.controller.buttonDown & A_BUTTON ~=0) then
e.spiralOvalProgressTicks = e.spiralOvalProgressTicks+timeStep
end
if e.spiralTime_cur>=spiralTime_max or m.controller.buttonPressed & B_BUTTON ~=0 then
local flingSpeed = vec3f_dist(prevPos,m.pos) --NOTE: don't need to divide by time since it's 1 tick AKA divided by 1
vec3f_copy(e.flingVec,m.pos)
vec3f_sub(e.flingVec,prevPos)
vec3f_normalize(e.flingVec)
vec3f_mul(e.flingVec,flingSpeed)
play_sound_if_no_flag(m,SOUND_MARIO_YAHOO,MARIO_MARIO_SOUND_PLAYED)
play_sound(SOUND_GENERAL_BOING1,m.marioObj.header.gfx.cameraToObject)
set_mario_action(m,ACT_SPIRALMARIO_FLING,0)
end
end
hook_event(HOOK_MARIO_UPDATE, mario_update)
hook_event(HOOK_ON_PLAYER_CONNECTED, initExtrasByPlayer)
hook_event(HOOK_ON_PLAYER_DISCONNECTED, initExtrasByPlayer)
hook_mario_action(ACT_SPIRALMARIO_SPIRAL, act_spiralmario_spiral)
hook_mario_action(ACT_SPIRALMARIO_FLING, act_spiralmario_fling)
for i=0,(MAX_PLAYERS-1) do
initExtrasByIndex(i)
end