mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2026-04-29 21:41:53 +00:00
Remove Character Select and Subsequent Mods (#1185)
Some checks are pending
Build coop / build-linux (push) Waiting to run
Build coop / build-steamos (push) Waiting to run
Build coop / build-windows-opengl (push) Waiting to run
Build coop / build-windows-directx (push) Waiting to run
Build coop / build-macos-arm (push) Waiting to run
Build coop / build-macos-intel (push) Waiting to run
Some checks are pending
Build coop / build-linux (push) Waiting to run
Build coop / build-steamos (push) Waiting to run
Build coop / build-windows-opengl (push) Waiting to run
Build coop / build-windows-directx (push) Waiting to run
Build coop / build-macos-arm (push) Waiting to run
Build coop / build-macos-intel (push) Waiting to run
This commit is contained in:
parent
24c5a226ed
commit
bdd34bdd3e
818 changed files with 0 additions and 68334 deletions
Binary file not shown.
|
|
@ -1,93 +0,0 @@
|
|||
--- Don't add any functional code to this file ---
|
||||
--- @meta
|
||||
|
||||
--- @class LuigiState
|
||||
|
||||
--- @class ToadState
|
||||
|
||||
--- @class WarioState
|
||||
|
||||
--- @class WaluigiState
|
||||
|
||||
--- @class ToadetteState
|
||||
--- @field public averageForwardVel number
|
||||
|
||||
--- @class PeachState
|
||||
|
||||
--- @class DaisyState
|
||||
|
||||
--- @class YoshiState
|
||||
|
||||
--- @class BirdoState
|
||||
--- @field public spitTimer integer
|
||||
--- @field public framesSinceShoot integer
|
||||
--- @field public flameCharge integer
|
||||
|
||||
--- @class SpikeState
|
||||
|
||||
--- @class PaulineState
|
||||
|
||||
--- @class RosalinaState
|
||||
--- @field public canSpin boolean
|
||||
--- @field public orbitObjActive boolean
|
||||
--- @field public orbitObjDist number
|
||||
--- @field public orbitObjAngle integer
|
||||
|
||||
--- @class WapeachState
|
||||
|
||||
--- @class DonkeyKongState
|
||||
|
||||
--- @class SonicState
|
||||
--- @field public spinCharge integer
|
||||
--- @field public groundYVel integer
|
||||
--- @field public prevForwardVel integer
|
||||
--- @field public peakHeight integer
|
||||
--- @field public actionADone boolean
|
||||
--- @field public actionBDone boolean
|
||||
--- @field public bounced boolean
|
||||
--- @field public spindashState integer
|
||||
--- @field public instashieldTimer integer
|
||||
--- @field public oxygen integer
|
||||
--- @field public prevVelY number
|
||||
--- @field public prevHeight number
|
||||
--- @field public physTimer integer
|
||||
--- @field public lastforwardPos Vec3f
|
||||
--- @field public realFVel number
|
||||
|
||||
--- @class CharacterState
|
||||
--- @field public mario MarioState
|
||||
--- @field public luigi LuigiState
|
||||
--- @field public toad ToadState
|
||||
--- @field public wario WarioState
|
||||
--- @field public waluigi WaluigiState
|
||||
--- @field public toadette ToadetteState
|
||||
--- @field public peach PeachState
|
||||
--- @field public daisy DaisyState
|
||||
--- @field public yoshi YoshiState
|
||||
--- @field public birdo BirdoState
|
||||
--- @field public spike SpikeState
|
||||
--- @field public pauline PaulineState
|
||||
--- @field public rosalina RosalinaState
|
||||
--- @field public wapeach WapeachState
|
||||
--- @field public donkeyKong DonkeyKongState
|
||||
--- @field public sonic SonicState
|
||||
|
||||
--- @alias SonicMouthGSCId
|
||||
--- | `SONIC_MOUTH_NORMAL`
|
||||
--- | `SONIC_MOUTH_FROWN`
|
||||
--- | `SONIC_MOUTH_GRIMACING`
|
||||
--- | `SONIC_MOUTH_HAPPY`
|
||||
--- | `SONIC_MOUTH_GRIN`
|
||||
--- | `SONIC_MOUTH_ATTACKED`
|
||||
--- | `SONIC_MOUTH_SHOCKED`
|
||||
--- | `SONIC_MOUTH_SURPRISED`
|
||||
--- | `SONIC_MOUTH_NEUTRAL`
|
||||
|
||||
--- @alias SonicMouthSideGSCId
|
||||
--- | `SONIC_MOUTH_LEFT`
|
||||
--- | `SONIC_MOUTH_RIGHT`
|
||||
|
||||
--- @alias HandParam
|
||||
--- | `SONIC_HAND_RIGHT`
|
||||
--- | `SONIC_HAND_LEFT`
|
||||
--- | `WAPEACH_HAND_AXE`
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
-- Environment inclusions --
|
||||
--[[
|
||||
We only need to include character select rn
|
||||
]]
|
||||
|
||||
charSelect = charSelect
|
||||
|
||||
if not charSelect then return end
|
||||
_ENV = setmetatable(_G, { __index = charSelect })
|
||||
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
--- Misc Functions ---
|
||||
|
||||
--- @param m MarioState
|
||||
--- @param name string
|
||||
--- @param accel? number
|
||||
--- Plays a custom animation for MarioState `m`
|
||||
function play_custom_anim(m, name, accel)
|
||||
accel = accel or 0x10000
|
||||
|
||||
m.marioObj.header.gfx.animInfo.animAccel = accel
|
||||
|
||||
if (smlua_anim_util_get_current_animation_name(m.marioObj) ~= name or m.marioObj.header.gfx.animInfo.animID ~= -1) then
|
||||
m.marioObj.header.gfx.animInfo.animID = -1
|
||||
set_anim_to_frame(m, 0)
|
||||
end
|
||||
|
||||
smlua_anim_util_set_animation(m.marioObj, name)
|
||||
end
|
||||
|
||||
--- @param str string
|
||||
--- @param splitAt? string
|
||||
function string.split(str, splitAt)
|
||||
if splitAt == nil then
|
||||
splitAt = " "
|
||||
end
|
||||
local result = {}
|
||||
for match in str:gmatch(string.format("[^%s]+", splitAt)) do
|
||||
table.insert(result, match)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
|
@ -1,148 +0,0 @@
|
|||
local colObjLists = { OBJ_LIST_GENACTOR, OBJ_LIST_PUSHABLE, OBJ_LIST_SURFACE, OBJ_LIST_DESTRUCTIVE }
|
||||
|
||||
local bhvBlacklist = {
|
||||
[id_bhvBowser] = true,
|
||||
[id_bhvDoor] = true,
|
||||
[id_bhvDoorWarp] = true,
|
||||
[id_bhvStarDoor] = true,
|
||||
[id_bhvUnlockDoorStar] = true,
|
||||
[id_bhvToadMessage] = true,
|
||||
[id_bhvFireSpitter] = true,
|
||||
[id_bhvExplosion] = true
|
||||
}
|
||||
|
||||
---@param o Object
|
||||
---@param o2 Object
|
||||
local function attack_bounce(o, o2)
|
||||
o2.oVelY = 15.0
|
||||
play_sound(SOUND_ACTION_BONK, o2.header.gfx.cameraToObject)
|
||||
end
|
||||
|
||||
---@param o Object
|
||||
---@param o2 Object
|
||||
local function attack_bully(o, o2)
|
||||
o2.oBullyLastNetworkPlayerIndex = o.globalPlayerIndex
|
||||
o2.oMoveAngleYaw = o.oMoveAngleYaw
|
||||
o2.oForwardVel = 30.0
|
||||
|
||||
o2.oInteractStatus = o2.oInteractStatus | ATTACK_FAST_ATTACK | INT_STATUS_WAS_ATTACKED | INT_STATUS_INTERACTED
|
||||
end
|
||||
|
||||
---@param o Object
|
||||
---@param o2 Object
|
||||
local function attack_bully_strong(o, o2)
|
||||
o2.oBullyLastNetworkPlayerIndex = o.globalPlayerIndex
|
||||
o2.oMoveAngleYaw = o.oMoveAngleYaw
|
||||
o2.oForwardVel = 50.0
|
||||
o2.oVelY = 30.0
|
||||
|
||||
o2.oInteractStatus = o2.oInteractStatus | ATTACK_FAST_ATTACK | INT_STATUS_WAS_ATTACKED | INT_STATUS_INTERACTED
|
||||
end
|
||||
|
||||
---@param o Object
|
||||
---@param o2 Object
|
||||
local function attack_mrblizzard(o, o2)
|
||||
if o2.prevObj then
|
||||
o2.prevObj.oAction = 2
|
||||
o2.prevObj = nil
|
||||
o2.oMrBlizzardHeldObj = nil
|
||||
end
|
||||
o2.oAction = MR_BLIZZARD_ACT_DEATH
|
||||
end
|
||||
|
||||
---@param o Object
|
||||
---@param o2 Object
|
||||
local function attack_bullet_bill(o, o2)
|
||||
spawn_mist_particles_with_sound(SOUND_GENERAL2_BOBOMB_EXPLOSION)
|
||||
o2.oAction = 4
|
||||
o2.oTimer = 0
|
||||
end
|
||||
|
||||
---@param o Object
|
||||
---@param o2 Object
|
||||
local function attack_chuckya(o, o2)
|
||||
o2.oAction = 2
|
||||
o2.oVelY = 30
|
||||
o2.oMoveAngleYaw = o.oMoveAngleYaw
|
||||
o2.oForwardVel = 25
|
||||
end
|
||||
|
||||
---@param o Object
|
||||
---@param o2 Object
|
||||
local function attack_whomp(o, o2)
|
||||
o2.oAction = 8
|
||||
end
|
||||
|
||||
---@param o Object
|
||||
---@param o2 Object
|
||||
local function attack_kingbobomb(o, o2)
|
||||
if o2.oFlags & OBJ_FLAG_HOLDABLE ~= 0 and o2.oAction ~= 8 then
|
||||
o2.oVelY = 30
|
||||
o2.oForwardVel = 30
|
||||
o2.oMoveAngleYaw = o.oMoveAngleYaw
|
||||
o2.oMoveFlags = 0
|
||||
o2.oAction = 4
|
||||
end
|
||||
end
|
||||
|
||||
---@param o Object
|
||||
---@param o2 Object
|
||||
local function attack_wooden_post(o, o2)
|
||||
o2.oWoodenPostMarioPounding = 1
|
||||
o2.oWoodenPostSpeedY = -100.0
|
||||
cur_obj_play_sound_2(SOUND_GENERAL_POUND_WOOD_POST)
|
||||
end
|
||||
|
||||
-- lists for edge case interactions
|
||||
|
||||
bhvWapeachAxeAttacks = {
|
||||
[id_bhvSmallBully] = attack_bully_strong,
|
||||
[id_bhvBigBully] = attack_bully_strong,
|
||||
[id_bhvBigBullyWithMinions] = attack_bully_strong,
|
||||
[id_bhvSmallChillBully] = attack_bully_strong,
|
||||
[id_bhvBigChillBully] = attack_bully_strong,
|
||||
[id_bhvMrBlizzard] = attack_mrblizzard,
|
||||
[id_bhvBulletBill] = attack_bullet_bill,
|
||||
[id_bhvSmallWhomp] = attack_whomp,
|
||||
[id_bhvChuckya] = attack_chuckya,
|
||||
[id_bhvWoodenPost] = attack_wooden_post,
|
||||
}
|
||||
|
||||
---@param o Object
|
||||
---@param spAttacksList table<BehaviorId,function>
|
||||
---@param getTarget? boolean
|
||||
function obj_process_attacks(o, spAttacksList, getTarget)
|
||||
-- players
|
||||
if o.oInteractType == 0 then
|
||||
local m = nearest_mario_state_to_object(o)
|
||||
if m and m.playerIndex == 0 and m.marioObj.globalPlayerIndex ~= o.globalPlayerIndex
|
||||
and m.action & (ACT_FLAG_INVULNERABLE | ACT_FLAG_INTANGIBLE) == 0 and m.invincTimer == 0
|
||||
and obj_check_hitbox_overlap(m.marioObj, o) then
|
||||
if spAttacksList[id_bhvMario] then
|
||||
spAttacksList[id_bhvMario](o, m)
|
||||
else
|
||||
take_damage_and_knock_back(m, o)
|
||||
end
|
||||
if getTarget then return m.marioObj end
|
||||
end
|
||||
end
|
||||
-- other objects
|
||||
for i, list in ipairs(colObjLists) do
|
||||
local o2 = obj_get_first(list)
|
||||
while o2 do
|
||||
if o ~= o2 and o2.oInteractStatus & INT_STATUS_INTERACTED == 0 and o2.oIntangibleTimer == 0 and obj_check_hitbox_overlap(o, o2) then
|
||||
local bhv = get_id_from_behavior(o2.behavior)
|
||||
if not bhvBlacklist[bhv] then
|
||||
if spAttacksList[bhv] then
|
||||
spAttacksList[bhv](o, o2)
|
||||
else
|
||||
o2.oInteractStatus = o2.oInteractStatus | ATTACK_FAST_ATTACK | INT_STATUS_WAS_ATTACKED |
|
||||
INT_STATUS_INTERACTED
|
||||
end
|
||||
if getTarget then return o2 end
|
||||
end
|
||||
end
|
||||
o2 = obj_get_next(o2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
--- Vars that all movesets use --
|
||||
|
||||
--- @type CharacterState[]
|
||||
gCharacterStates = {}
|
||||
for i = 0, (MAX_PLAYERS - 1) do
|
||||
gCharacterStates[i] = {}
|
||||
local m = gMarioStates[i]
|
||||
local e = gCharacterStates[i]
|
||||
e.mario = m
|
||||
e.luigi = {}
|
||||
e.toad = {}
|
||||
e.wario = {}
|
||||
e.waluigi = {}
|
||||
e.toadette = {}
|
||||
e.peach = {}
|
||||
e.daisy = {}
|
||||
e.yoshi = {}
|
||||
e.birdo = {}
|
||||
e.spike = {}
|
||||
e.pauline = {}
|
||||
e.rosalina = {}
|
||||
e.wapeach = {}
|
||||
e.donkeyKong = {}
|
||||
e.sonic = {}
|
||||
|
||||
e.toadette.averageForwardVel = 0
|
||||
|
||||
e.birdo.spitTimer = 0
|
||||
e.birdo.framesSinceShoot = 255
|
||||
e.birdo.flameCharge = 0
|
||||
|
||||
e.rosalina.canSpin = true
|
||||
e.rosalina.orbitObjActive = false
|
||||
e.rosalina.orbitObjDist = 0
|
||||
e.rosalina.orbitObjAngle = 0
|
||||
|
||||
e.sonic.spinCharge = 0
|
||||
e.sonic.groundYVel = 0
|
||||
e.sonic.prevForwardVel = 0
|
||||
e.sonic.peakHeight = 0
|
||||
e.sonic.actionADone = false
|
||||
e.sonic.actionBDone = false
|
||||
e.sonic.bounced = false
|
||||
e.sonic.spindashState = 0
|
||||
e.sonic.instashieldTimer = 0
|
||||
e.sonic.oxygen = 900 -- 30 seconds
|
||||
e.sonic.prevVelY = 0
|
||||
e.sonic.prevHeight = 0
|
||||
e.sonic.physTimer = 0
|
||||
e.sonic.lastforwardPos = gVec3fZero()
|
||||
e.sonic.realFVel = 0
|
||||
end
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,843 +0,0 @@
|
|||
-------------------
|
||||
-- Birdo Moveset --
|
||||
-------------------
|
||||
|
||||
if not charSelect then return end
|
||||
|
||||
local SOUND_SPIT = audio_sample_load("z_sfx_birdo_spit.ogg") -- Load audio sample
|
||||
|
||||
---------------
|
||||
-- Birdo Egg --
|
||||
---------------
|
||||
|
||||
_G.ACT_BIRDO_HOLD_WALKING = allocate_mario_action(ACT_FLAG_MOVING | ACT_GROUP_OBJECT)
|
||||
_G.ACT_SPIT_EGG = allocate_mario_action(ACT_FLAG_STATIONARY | ACT_FLAG_IDLE | ACT_FLAG_ALLOW_FIRST_PERSON | ACT_FLAG_PAUSE_EXIT)
|
||||
_G.ACT_SPIT_EGG_WALK = allocate_mario_action(ACT_FLAG_MOVING | ACT_FLAG_ALLOW_FIRST_PERSON)
|
||||
_G.ACT_SPIT_EGG_AIR = allocate_mario_action(ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION | ACT_FLAG_CONTROL_JUMP_HEIGHT)
|
||||
|
||||
--- @param m MarioState
|
||||
local function act_birdo_hold_walking(m)
|
||||
local startYaw = m.faceAngle.y
|
||||
|
||||
if m.heldObj and m.heldObj.behavior == get_behavior_from_id(id_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
|
||||
|
||||
update_walking_speed(m) -- normal walking speed
|
||||
|
||||
local result = perform_ground_step(m)
|
||||
if result == GROUND_STEP_LEFT_GROUND then
|
||||
set_mario_action(m, ACT_HOLD_FREEFALL, 0)
|
||||
elseif result == GROUND_STEP_HIT_WALL then
|
||||
if (m.forwardVel > 16) then
|
||||
mario_set_forward_vel(m, 16)
|
||||
end
|
||||
end
|
||||
|
||||
-- for the animation, temporarily read birdo's speed as lower so it looks less goofy
|
||||
local prevForwardVel = m.forwardVel
|
||||
local prevMag = m.intendedMag
|
||||
m.forwardVel = m.forwardVel * 0.6
|
||||
m.intendedMag = m.intendedMag * 0.6
|
||||
anim_and_audio_for_hold_walk(m)
|
||||
m.forwardVel = prevForwardVel
|
||||
m.intendedMag = prevMag
|
||||
|
||||
|
||||
-- tilt body
|
||||
local dYaw = m.faceAngle.y - startYaw
|
||||
local val02 = -(dYaw * m.forwardVel / 12)
|
||||
local val00 = (m.forwardVel * 170)
|
||||
|
||||
val02 = math.clamp(val02, -0x1555, 0x1555)
|
||||
val00 = math.clamp(val00, 0x0, 0x1555)
|
||||
|
||||
m.marioBodyState.allowPartRotation = true
|
||||
m.marioBodyState.torsoAngle.z = approach_s32(m.marioBodyState.torsoAngle.z, val02, 0x400, 0x400)
|
||||
m.marioBodyState.torsoAngle.x = approach_s32(m.marioBodyState.torsoAngle.x, val00, 0x400, 0x400)
|
||||
|
||||
if (0.4 * m.intendedMag - m.forwardVel > 10) then
|
||||
set_mario_particle_flags(m, PARTICLE_DUST, 0)
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
--- @param m MarioState
|
||||
local function act_spit_egg(m)
|
||||
local e = gCharacterStates[m.playerIndex]
|
||||
if (m.quicksandDepth > 30) then
|
||||
return set_mario_action(m, ACT_IN_QUICKSAND, 0)
|
||||
end
|
||||
|
||||
if m.actionState == 0 then
|
||||
play_custom_anim(m, "BIRDO_ANIM_IDLE_TO_AIM_IDLE")
|
||||
if is_anim_past_end(m) ~= 0 then
|
||||
m.actionState = 1
|
||||
end
|
||||
elseif e.birdo.flameCharge == 0 and e.birdo.framesSinceShoot > 10 then
|
||||
play_custom_anim(m, "BIRDO_ANIM_AIM_IDLE_TO_IDLE")
|
||||
if is_anim_past_end(m) ~= 0 then
|
||||
return set_mario_action(m, ACT_IDLE, 0)
|
||||
end
|
||||
else
|
||||
play_custom_anim(m, "BIRDO_ANIM_AIM_IDLE")
|
||||
end
|
||||
mario_drop_held_object(m)
|
||||
|
||||
m.actionTimer = m.actionTimer + 1
|
||||
|
||||
local oldActTimer = m.actionTimer
|
||||
if (m.input & INPUT_NONZERO_ANALOG) ~= 0 then
|
||||
mario_set_forward_vel(m, 0)
|
||||
local result = set_mario_action(m, ACT_SPIT_EGG_WALK, 0)
|
||||
m.actionTimer = oldActTimer
|
||||
return result
|
||||
elseif (check_common_idle_cancels(m) ~= 0) then
|
||||
if m.action & ACT_FLAG_AIR ~= 0 then
|
||||
mario_set_forward_vel(m, 0)
|
||||
set_mario_action(m, ACT_SPIT_EGG_AIR, 1)
|
||||
if m.vel.y <= 0 then
|
||||
m.actionArg = 0
|
||||
end
|
||||
m.actionTimer = oldActTimer
|
||||
end
|
||||
return 1
|
||||
end
|
||||
|
||||
mario_set_forward_vel(m, 0)
|
||||
perform_ground_step(m)
|
||||
return 0
|
||||
end
|
||||
|
||||
--- @param m MarioState
|
||||
local function act_spit_egg_walk(m)
|
||||
local e = gCharacterStates[m.playerIndex]
|
||||
local mBody = m.marioBodyState
|
||||
|
||||
mario_drop_held_object(m)
|
||||
|
||||
m.actionTimer = m.actionTimer + 1
|
||||
if e.birdo.flameCharge == 0 and e.birdo.framesSinceShoot > 10 then
|
||||
if m.forwardVel < 0 then
|
||||
m.forwardVel = m.intendedMag
|
||||
m.faceAngle.y = m.intendedYaw
|
||||
return set_mario_action(m, ACT_FINISH_TURNING_AROUND, 0)
|
||||
end
|
||||
m.forwardVel = m.intendedMag
|
||||
m.faceAngle.y = m.intendedYaw
|
||||
return set_mario_action(m, ACT_WALKING, 0)
|
||||
end
|
||||
|
||||
if mario_floor_is_slippery(m) ~= 0 then
|
||||
return set_mario_action(m, ACT_WALKING, 0)
|
||||
end
|
||||
|
||||
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
|
||||
m.intendedMag = 0
|
||||
if m.slideVelX == 0 and m.slideVelZ == 0 then
|
||||
return begin_braking_action(m)
|
||||
end
|
||||
end
|
||||
|
||||
if (m.input & INPUT_ZERO_MOVEMENT) ~= 0 and m.slideVelX == 0 and m.slideVelZ == 0 then
|
||||
local oldActTimer = m.actionTimer
|
||||
local result = set_mario_action(m, ACT_SPIT_EGG, 0)
|
||||
m.actionTimer = oldActTimer
|
||||
return result
|
||||
end
|
||||
|
||||
if (m.input & INPUT_Z_PRESSED) ~= 0 then
|
||||
return set_mario_action(m, ACT_CROUCH_SLIDE, 0)
|
||||
end
|
||||
|
||||
-- strafe movement
|
||||
local newVelX = sins(m.intendedYaw) * m.intendedMag
|
||||
local newVelZ = coss(m.intendedYaw) * m.intendedMag
|
||||
m.slideVelX = approach_f32(m.slideVelX, newVelX, 4, 4)
|
||||
m.slideVelZ = approach_f32(m.slideVelZ, newVelZ, 4, 4)
|
||||
m.vel.x, m.vel.z = m.slideVelX, m.slideVelZ
|
||||
m.forwardVel = math.sqrt(m.vel.x ^ 2 + m.vel.z ^ 2)
|
||||
|
||||
if (m.input & INPUT_A_PRESSED) ~= 0 then
|
||||
set_mario_y_vel_based_on_fspeed(m, 42, 0.25)
|
||||
m.slideVelX = m.slideVelX * 0.8
|
||||
m.slideVelZ = m.slideVelZ * 0.8
|
||||
m.vel.x, m.vel.z = m.slideVelX, m.slideVelZ
|
||||
m.forwardVel = m.forwardVel * 0.8
|
||||
local oldActTimer = m.actionTimer
|
||||
local result = set_mario_action(m, ACT_SPIT_EGG_AIR, 1)
|
||||
m.actionTimer = oldActTimer
|
||||
return result
|
||||
end
|
||||
|
||||
local result = (perform_ground_step(m))
|
||||
if result == GROUND_STEP_LEFT_GROUND then
|
||||
m.vel.y = 0
|
||||
local oldActTimer = m.actionTimer
|
||||
set_mario_action(m, ACT_SPIT_EGG_AIR, 0)
|
||||
m.actionTimer = oldActTimer
|
||||
--set_character_animation(m, CHAR_ANIM_GENERAL_FALL)
|
||||
elseif result == GROUND_STEP_NONE then
|
||||
--anim_and_audio_for_walk(m)
|
||||
play_step_sound(m, 10, 49)
|
||||
|
||||
local dYaw = math.s16(m.faceAngle.y - m.intendedYaw)
|
||||
play_custom_anim(m, "BIRDO_ANIM_AIM_WALK", m.forwardVel / 4 * 0x10000)
|
||||
|
||||
mBody.allowPartRotation = true
|
||||
m.marioObj.header.gfx.angle.y = m.intendedYaw
|
||||
local marioAnimInfo = m.marioObj.header.gfx.animInfo
|
||||
if math.abs(dYaw) > 0x4000 then
|
||||
m.marioObj.header.gfx.angle.y = m.intendedYaw - 0x8000
|
||||
marioAnimInfo.animAccel = -math.abs(marioAnimInfo.animAccel)
|
||||
else
|
||||
marioAnimInfo.animAccel = math.abs(marioAnimInfo.animAccel)
|
||||
end
|
||||
|
||||
-- Handle manually the loop points of the animation if moving backwards
|
||||
if marioAnimInfo.animAccel < 0 and marioAnimInfo.animFrame <= marioAnimInfo.curAnim.loopStart then
|
||||
marioAnimInfo.animFrame = marioAnimInfo.curAnim.loopEnd
|
||||
marioAnimInfo.animFrameAccelAssist = marioAnimInfo.animFrame << 16
|
||||
end
|
||||
|
||||
mBody.torsoAngle.y = math.s16(m.faceAngle.y - m.marioObj.header.gfx.angle.y) * 0.4
|
||||
mBody.headAngle.y = m.faceAngle.y - m.marioObj.header.gfx.angle.y - mBody.torsoAngle.y
|
||||
|
||||
if m.intendedMag - m.forwardVel > 16 then
|
||||
set_mario_particle_flags(m, PARTICLE_DUST, 0)
|
||||
end
|
||||
end
|
||||
|
||||
check_ledge_climb_down(m)
|
||||
return 0
|
||||
end
|
||||
|
||||
---@param m MarioState
|
||||
local function act_spit_egg_air(m)
|
||||
local e = gCharacterStates[m.playerIndex]
|
||||
|
||||
play_custom_anim(m, "BIRDO_ANIM_AIM_JUMP")
|
||||
if m.actionArg ~= 1 then
|
||||
set_anim_to_frame(m, m.marioObj.header.gfx.animInfo.curAnim.loopEnd)
|
||||
else
|
||||
play_mario_sound(m, SOUND_ACTION_TERRAIN_JUMP, 0)
|
||||
end
|
||||
|
||||
m.actionTimer = m.actionTimer + 1
|
||||
|
||||
if (m.input & INPUT_Z_PRESSED) ~= 0 then
|
||||
return set_mario_action(m, ACT_GROUND_POUND, 0)
|
||||
end
|
||||
|
||||
-- air strafe
|
||||
local newVelX = sins(m.intendedYaw) * m.intendedMag
|
||||
local newVelZ = coss(m.intendedYaw) * m.intendedMag
|
||||
m.slideVelX = approach_f32(m.slideVelX, newVelX, 1, 1)
|
||||
m.slideVelZ = approach_f32(m.slideVelZ, newVelZ, 1, 1)
|
||||
m.vel.x, m.vel.z = m.slideVelX, m.slideVelZ
|
||||
m.forwardVel = m.slideVelX * sins(m.faceAngle.y) + m.slideVelZ * coss(m.faceAngle.y)
|
||||
--local absSpeed = math.max(math.abs(m.slideVelX), math.abs(m.slideVelZ))
|
||||
|
||||
local result = (perform_air_step(m, 0))
|
||||
if result == AIR_STEP_LANDED then
|
||||
if check_fall_damage_or_get_stuck(m, ACT_HARD_BACKWARD_GROUND_KB) ~= 0 then
|
||||
return 1
|
||||
elseif e.birdo.flameCharge == 0 and e.birdo.framesSinceShoot > 10 then
|
||||
set_mario_action(m, ACT_FREEFALL_LAND, 0)
|
||||
else
|
||||
local oldActTimer = m.actionTimer
|
||||
set_mario_action(m, ACT_SPIT_EGG_WALK, 0)
|
||||
m.actionTimer = oldActTimer
|
||||
end
|
||||
return 1
|
||||
elseif result == AIR_STEP_HIT_WALL then
|
||||
mario_set_forward_vel(m, 0)
|
||||
elseif result == AIR_STEP_HIT_LAVA_WALL then
|
||||
lava_boost_on_wall(m)
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
-- Egg
|
||||
|
||||
local eggIntObjLists = {
|
||||
OBJ_LIST_GENACTOR,
|
||||
OBJ_LIST_PUSHABLE,
|
||||
OBJ_LIST_SURFACE,
|
||||
OBJ_LIST_PLAYER,
|
||||
}
|
||||
|
||||
E_MODEL_EGG = smlua_model_util_get_id("egg_geo")
|
||||
---@param o Object
|
||||
function bhv_birdo_egg_init(o)
|
||||
o.oFlags = (OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE | OBJ_FLAG_SET_FACE_YAW_TO_MOVE_YAW | OBJ_FLAG_HOLDABLE | OBJ_FLAG_COMPUTE_DIST_TO_MARIO)
|
||||
o.oFaceAngleRoll = 0
|
||||
o.oMoveAngleRoll = 0
|
||||
o.oGravity = 0
|
||||
o.oBounciness = 0
|
||||
o.oFriction = 1
|
||||
o.oDragStrength = 0
|
||||
o.oBuoyancy = 0
|
||||
o.oWallHitboxRadius = 60
|
||||
o.oVelY = 0
|
||||
|
||||
o.collisionData = smlua_collision_util_get("egg_collision")
|
||||
|
||||
local hitbox = get_temp_object_hitbox()
|
||||
hitbox.interactType = INTERACT_DAMAGE
|
||||
hitbox.hurtboxRadius = 60
|
||||
hitbox.hurtboxHeight = 80
|
||||
hitbox.downOffset = 80
|
||||
hitbox.radius = 60
|
||||
hitbox.height = 80
|
||||
hitbox.damageOrCoinValue = 1
|
||||
if o.oBehParams ~= 0 then
|
||||
-- similar hitbox to fire spitter flames
|
||||
hitbox.interactType = INTERACT_FLAME
|
||||
hitbox.radius = 10
|
||||
hitbox.height = 40
|
||||
hitbox.hurtboxRadius = 10
|
||||
hitbox.hurtboxHeight = 40
|
||||
hitbox.downOffset = 30
|
||||
obj_set_billboard(o)
|
||||
o.header.gfx.scale.x = 3
|
||||
o.header.gfx.scale.y = 3
|
||||
o.header.gfx.scale.z = 3
|
||||
end
|
||||
obj_set_hitbox(o, hitbox)
|
||||
o.oIntangibleTimer = 10
|
||||
|
||||
-- do manual shadow, otherwise the shadow renders on top of itself
|
||||
o.header.gfx.disableAutomaticShadowPos = true
|
||||
o.header.gfx.shadowPos.x = o.oPosX
|
||||
o.header.gfx.shadowPos.y = o.oPosY - 50
|
||||
o.header.gfx.shadowPos.z = o.oPosZ
|
||||
|
||||
network_init_object(o, true, { 'globalPlayerIndex' })
|
||||
end
|
||||
|
||||
---@param o Object
|
||||
function bhv_birdo_egg_loop(o)
|
||||
if o.oBehParams ~= 0 then
|
||||
o.oAnimState = o.oAnimState + 1
|
||||
end
|
||||
|
||||
if o.oHeldState == HELD_FREE then
|
||||
cur_obj_enable_rendering()
|
||||
if o.oAction == 0 then
|
||||
o.oGravity = 0
|
||||
else
|
||||
o.oMoveAnglePitch = 0
|
||||
o.oFaceAnglePitch = 0
|
||||
o.oGravity = -2
|
||||
end
|
||||
|
||||
cur_obj_update_floor_and_walls()
|
||||
local oldForwardVel = o.oForwardVel
|
||||
if o.oAction == 0 then
|
||||
obj_compute_vel_from_move_pitch(o.oForwardVel)
|
||||
end
|
||||
cur_obj_move_standard(60)
|
||||
o.oForwardVel = oldForwardVel
|
||||
|
||||
local defaultVel = 20
|
||||
if o.oBehParams ~= 0 then
|
||||
defaultVel = 40
|
||||
end
|
||||
if o.oAction == 0 and o.oForwardVel > defaultVel then
|
||||
o.oForwardVel = approach_f32(o.oForwardVel, defaultVel, 3, 3)
|
||||
end
|
||||
|
||||
-- manual object collision
|
||||
local dieFromCollision = false
|
||||
o.numCollidedObjs = obj_attack_collided_from_other_object(o)
|
||||
if o.numCollidedObjs ~= 0 and o.oBehParams == 0 then
|
||||
dieFromCollision = true
|
||||
end
|
||||
if o.oDistanceToMario < 2000 then
|
||||
for _, list in ipairs(eggIntObjLists) do
|
||||
local o2 = obj_get_first(list)
|
||||
while o2 and o.numCollidedObjs < 4 do
|
||||
if o ~= o2 then
|
||||
if list ~= OBJ_LIST_PLAYER and o2.oHeldState == HELD_FREE and detect_object_hitbox_overlap(o, o2) ~= 0 then
|
||||
o2.numCollidedObjs = o2.numCollidedObjs - 1 -- prevent game crash
|
||||
local doEggInteract = birdo_egg_interaction(o2, o)
|
||||
if o.oBehParams == 0 or doEggInteract then
|
||||
dieFromCollision = true
|
||||
end
|
||||
if doEggInteract or o2.oInteractType == INTERACT_BREAKABLE or obj_is_attackable(o2) then
|
||||
if obj_has_behavior_id(o2, id_bhvBowser) == 0 then
|
||||
o2.oInteractStatus = o2.oInteractStatus | ATTACK_PUNCH | INT_STATUS_WAS_ATTACKED |
|
||||
INT_STATUS_INTERACTED | INT_STATUS_TOUCHED_BOB_OMB
|
||||
end
|
||||
end
|
||||
elseif o.oBehParams ~= 0 and birdo_fire_is_targettable(o2, o) and dist_between_objects(o2, o) <= 700 then
|
||||
local angleToObject = obj_angle_to_object(o, o2)
|
||||
if abs_angle_diff(o.oMoveAngleYaw, angleToObject) <= 0x4000 then
|
||||
cur_obj_rotate_yaw_toward(angleToObject, 0x200)
|
||||
end
|
||||
end
|
||||
end
|
||||
o2 = obj_get_next(o2)
|
||||
end
|
||||
if o.numCollidedObjs >= 4 then break end
|
||||
end
|
||||
end
|
||||
|
||||
-- surface collision
|
||||
if o.oAction == 0 and o.oBehParams == 0 and o.oMoveFlags & OBJ_MOVE_MASK_IN_WATER == 0 then
|
||||
local m0 = gMarioStates[0]
|
||||
load_object_collision_model()
|
||||
if cur_obj_is_mario_on_platform() ~= 0 then
|
||||
if (m0.action == ACT_PUNCHING or m0.action == ACT_MOVE_PUNCHING) then
|
||||
-- pick up egg
|
||||
m0.heldObj = o
|
||||
m0.marioBodyState.grabPos = GRAB_POS_LIGHT_OBJ
|
||||
o.heldByPlayerIndex = 0
|
||||
o.oHeldState = HELD_HELD
|
||||
set_mario_action(m0, ACT_HOLD_FREEFALL, 0)
|
||||
if (o.oSyncID ~= 0) then network_send_object(o, false) end
|
||||
elseif (m0.prevAction & ACT_FLAG_AIR) ~= 0 then -- prevent falling off of egg easily
|
||||
m0.pos.x = o.oPosX
|
||||
m0.pos.z = o.oPosZ
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if dieFromCollision or o.oMoveFlags & (OBJ_MOVE_HIT_WALL | OBJ_MOVE_UNDERWATER_ON_GROUND | OBJ_MOVE_MASK_ON_GROUND) ~= 0 or o.oTimer > 120 then
|
||||
o.numCollidedObjs = 0
|
||||
spawn_mist_particles()
|
||||
obj_mark_for_deletion(o)
|
||||
end
|
||||
o.oInteractStatus = 0
|
||||
o.numCollidedObjs = 0
|
||||
elseif o.oHeldState == HELD_HELD then
|
||||
o.oFaceAnglePitch = 0
|
||||
o.oMoveAnglePitch = 0
|
||||
o.oInteractType = INTERACT_GRABBABLE
|
||||
cur_obj_disable_rendering_and_become_intangible(o)
|
||||
elseif o.oHeldState == HELD_THROWN then
|
||||
o.oFaceAnglePitch = 0
|
||||
o.oMoveAnglePitch = 0
|
||||
o.oInteractType = INTERACT_DAMAGE
|
||||
cur_obj_enable_rendering_and_become_tangible(o)
|
||||
cur_obj_change_action(1)
|
||||
local m = gMarioStates[o.heldByPlayerIndex]
|
||||
o.oForwardVel = math.max(m.forwardVel + 15, 40)
|
||||
o.oVelY = 10
|
||||
o.oTimer = 0
|
||||
o.oHeldState = HELD_FREE
|
||||
o.oIntangibleTimer = 10
|
||||
elseif o.oHeldState == HELD_DROPPED then
|
||||
spawn_mist_particles()
|
||||
obj_mark_for_deletion(o)
|
||||
end
|
||||
|
||||
-- do manual shadow, otherwise the shadow renders on top of itself
|
||||
if o.activeFlags ~= ACTIVE_FLAG_DEACTIVATED then
|
||||
o.header.gfx.disableAutomaticShadowPos = true
|
||||
o.header.gfx.shadowPos.x = o.oPosX
|
||||
o.header.gfx.shadowPos.y = o.oPosY - 50
|
||||
o.header.gfx.shadowPos.z = o.oPosZ
|
||||
else
|
||||
o.header.gfx.disableAutomaticShadowPos = false
|
||||
end
|
||||
end
|
||||
|
||||
-- lua recreation
|
||||
---@param a Object
|
||||
---@param b Object
|
||||
function detect_object_hitbox_overlap(a, b)
|
||||
if not (a and b) then return 0 end
|
||||
local sp3C = a.oPosY - a.hitboxDownOffset
|
||||
local sp38 = b.oPosY - b.hitboxDownOffset
|
||||
local dx = a.oPosX - b.oPosX
|
||||
local dz = a.oPosZ - b.oPosZ
|
||||
local collisionRadius = a.hitboxRadius + b.hitboxRadius
|
||||
local distance = math.floor(math.sqrt(dx * dx + dz * dz))
|
||||
|
||||
-- do not check for player interactions here
|
||||
if ((a.oInteractType & INTERACT_PLAYER) ~= 0 and (b.oInteractType & INTERACT_PLAYER) ~= 0) then
|
||||
return 0
|
||||
end
|
||||
|
||||
if (collisionRadius > distance) then
|
||||
local sp20 = a.hitboxHeight + sp3C
|
||||
local sp1C = b.hitboxHeight + sp38
|
||||
|
||||
if (sp3C > sp1C) then
|
||||
return 0
|
||||
end
|
||||
if (sp20 < sp38) then
|
||||
return 0
|
||||
end
|
||||
if (a.numCollidedObjs >= 4) then
|
||||
return 0
|
||||
end
|
||||
if (b.numCollidedObjs >= 4) then
|
||||
return 0
|
||||
end
|
||||
-- can't reference these fields in lua
|
||||
--a.collidedObjs[a.numCollidedObjs] = b
|
||||
--b.collidedObjs[b.numCollidedObjs] = a
|
||||
a.collidedObjInteractTypes = a.collidedObjInteractTypes | b.oInteractType
|
||||
b.collidedObjInteractTypes = b.collidedObjInteractTypes | a.oInteractType
|
||||
a.numCollidedObjs = a.numCollidedObjs + 1
|
||||
b.numCollidedObjs = b.numCollidedObjs + 1
|
||||
return 1
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
id_bhvBirdoEgg = hook_behavior(nil, OBJ_LIST_SURFACE, true, bhv_birdo_egg_init, bhv_birdo_egg_loop, "bhvBirdoEgg")
|
||||
|
||||
---@param m MarioState
|
||||
function birdo_update(m)
|
||||
-- spit egg
|
||||
local e = gCharacterStates[m.playerIndex]
|
||||
local inSpitAction = (m.action == ACT_SPIT_EGG or m.action == ACT_SPIT_EGG_WALK or m.action == ACT_SPIT_EGG_AIR or m.action == ACT_FIRST_PERSON or m.action == ACT_WATER_PUNCH or m.action == ACT_FLYING)
|
||||
local headRot = m.marioBodyState.headAngle
|
||||
|
||||
if m.controller.buttonPressed & B_BUTTON ~= 0 and inSpitAction then
|
||||
-- when mashing B, stay in spit action
|
||||
e.birdo.framesSinceShoot = 0
|
||||
if e.birdo.spitTimer == 0 then
|
||||
e.birdo.flameCharge = 0
|
||||
end
|
||||
else
|
||||
-- handle shooting repeatedly/charging
|
||||
if e.birdo.framesSinceShoot ~= 255 then
|
||||
e.birdo.framesSinceShoot = e.birdo.framesSinceShoot + 1
|
||||
end
|
||||
if m.controller.buttonDown & B_BUTTON ~= 0 then
|
||||
if inSpitAction then
|
||||
e.birdo.flameCharge = e.birdo.flameCharge + 1
|
||||
end
|
||||
elseif e.birdo.spitTimer < 25 then
|
||||
if e.birdo.flameCharge >= 30 then
|
||||
e.birdo.framesSinceShoot = 0 -- shoot fireball
|
||||
else
|
||||
e.birdo.flameCharge = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (e.birdo.framesSinceShoot <= 10 or e.birdo.flameCharge ~= 0) and not m.heldObj and inSpitAction then
|
||||
local canShoot = true
|
||||
local eggCount = 0
|
||||
local gIndex = network_global_index_from_local(m.playerIndex)
|
||||
local egg = obj_get_first_with_behavior_id(id_bhvBirdoEgg)
|
||||
while egg do
|
||||
if egg.oAction == 0 and egg.oHeldState == HELD_FREE and egg.globalPlayerIndex == gIndex then
|
||||
eggCount = eggCount + 1
|
||||
if eggCount >= 3 then -- max of 3 eggs/fireballs per player
|
||||
canShoot = false
|
||||
break
|
||||
end
|
||||
end
|
||||
egg = obj_get_next_with_same_behavior_id(egg)
|
||||
end
|
||||
|
||||
if e.birdo.spitTimer ~= 0 then
|
||||
e.birdo.spitTimer = e.birdo.spitTimer - 1
|
||||
m.marioBodyState.allowPartRotation = true
|
||||
if e.birdo.spitTimer > 24 then
|
||||
headRot.x = approach_f32(headRot.x, degrees_to_sm64(-30), degrees_to_sm64(10), degrees_to_sm64(10))
|
||||
else
|
||||
headRot.x = approach_f32(headRot.x, degrees_to_sm64(0), degrees_to_sm64(3.5), degrees_to_sm64(3.5))
|
||||
end
|
||||
end
|
||||
if e.birdo.spitTimer == 0 and canShoot and e.birdo.framesSinceShoot <= 10 then
|
||||
m.actionTimer = 0
|
||||
m.actionArg = 0
|
||||
end
|
||||
|
||||
local mouthPos = gVec3fZero()
|
||||
local yaw = m.faceAngle.y
|
||||
local pitch = 0
|
||||
if canShoot then
|
||||
-- when swimming, flying, or in first person, allow shooting in any direction
|
||||
if m.action == ACT_FIRST_PERSON then
|
||||
yaw = m.statusForCamera.headRotation.y + yaw
|
||||
pitch = m.statusForCamera.headRotation.x
|
||||
mouthPos.x = m.pos.x + sins(yaw) * 60 * coss(pitch)
|
||||
mouthPos.y = m.pos.y + 120 - sins(pitch) * 120
|
||||
mouthPos.z = m.pos.z + coss(yaw) * 60 * coss(pitch)
|
||||
elseif m.action & ACT_FLAG_SWIMMING_OR_FLYING ~= 0 then
|
||||
pitch = -m.faceAngle.x
|
||||
if pitch < 0 then
|
||||
mouthPos.x = m.pos.x + sins(yaw) * 80 * coss(pitch)
|
||||
mouthPos.y = m.pos.y + 120
|
||||
mouthPos.z = m.pos.z + coss(yaw) * 80 * coss(pitch)
|
||||
else
|
||||
mouthPos.x = m.pos.x + sins(yaw) * 80
|
||||
mouthPos.y = m.pos.y + 120 - sins(pitch) * 150
|
||||
mouthPos.z = m.pos.z + coss(yaw) * 80
|
||||
end
|
||||
else
|
||||
mouthPos.x = m.marioBodyState.headPos.x + sins(yaw + m.marioBodyState.headAngle.y) * 60
|
||||
mouthPos.y = m.marioBodyState.headPos.y + 20
|
||||
mouthPos.z = m.marioBodyState.headPos.z + coss(yaw + m.marioBodyState.headAngle.y) * 60
|
||||
end
|
||||
end
|
||||
|
||||
if canShoot and e.birdo.spitTimer == 0 and e.birdo.flameCharge >= 30 and m.action & ACT_FLAG_SWIMMING == 0 then
|
||||
spawn_non_sync_object(id_bhvKoopaShellFlame, E_MODEL_RED_FLAME,
|
||||
mouthPos.x,
|
||||
mouthPos.y,
|
||||
mouthPos.z,
|
||||
function(o)
|
||||
o.oKoopaShellFlameUnkF8 = 2
|
||||
o.oMoveAngleYaw = math.random(0, 0xFFFF)
|
||||
o.oVelY = math.random(10)
|
||||
o.oAnimState = math.random(10)
|
||||
o.oGravity = -4.0
|
||||
o.oTimer = 1
|
||||
o.oForwardVel = math.random(10)
|
||||
end)
|
||||
play_sound(SOUND_AIR_BLOW_FIRE, m.marioObj.header.gfx.cameraToObject)
|
||||
end
|
||||
|
||||
if canShoot and e.birdo.spitTimer == 0 and e.birdo.framesSinceShoot <= 10 then
|
||||
e.birdo.spitTimer = 30
|
||||
elseif e.birdo.spitTimer == 25 then
|
||||
local model = E_MODEL_EGG
|
||||
local isFireball = (e.birdo.flameCharge >= 30)
|
||||
if isFireball then
|
||||
model = E_MODEL_RED_FLAME
|
||||
e.birdo.flameCharge = 0
|
||||
end
|
||||
|
||||
if not isFireball then
|
||||
audio_sample_play(SOUND_SPIT, m.pos, 1) -- Play audio sample
|
||||
else
|
||||
play_sound(SOUND_AIR_BOWSER_SPIT_FIRE, m.marioObj.header.gfx.cameraToObject)
|
||||
end
|
||||
|
||||
if m.playerIndex == 0 then
|
||||
local eggVel = m.forwardVel * 2 + 25
|
||||
-- add double floor velocity to prevent being able to platform on eggs forever
|
||||
if m.floor and m.floor.object and m.floor.object.oForwardVel ~= 0 then
|
||||
eggVel = eggVel + m.floor.object.oForwardVel * 2
|
||||
end
|
||||
spawn_sync_object(id_bhvBirdoEgg, model, mouthPos.x + sins(yaw) * 40 * coss(pitch), mouthPos.y,
|
||||
mouthPos.z + coss(yaw) * 40 * coss(pitch), function(o)
|
||||
o.oForwardVel = math.max(eggVel, 40)
|
||||
o.oMoveAngleYaw = yaw
|
||||
o.oFaceAnglePitch = pitch
|
||||
o.oMoveAnglePitch = pitch
|
||||
o.oIntangibleTimer = 100
|
||||
o.globalPlayerIndex = gIndex
|
||||
o.oBehParams = (isFireball and 1) or 0
|
||||
spawn_mist_particles_variable(20, 120, 5)
|
||||
end)
|
||||
end
|
||||
end
|
||||
elseif e.birdo.spitTimer ~= 0 then
|
||||
e.birdo.spitTimer = e.birdo.spitTimer - 1
|
||||
m.marioBodyState.allowPartRotation = true
|
||||
if e.birdo.spitTimer > 24 then
|
||||
headRot.x = approach_f32(headRot.x, degrees_to_sm64(-30), degrees_to_sm64(10), degrees_to_sm64(10))
|
||||
else
|
||||
headRot.x = approach_f32(headRot.x, degrees_to_sm64(0), degrees_to_sm64(3.5), degrees_to_sm64(3.5))
|
||||
end
|
||||
end
|
||||
|
||||
-- throw objects instantly
|
||||
if m.action == ACT_THROWING then
|
||||
if m.actionTimer < 6 then
|
||||
m.actionTimer = 6
|
||||
set_anim_to_frame(m, 6)
|
||||
end
|
||||
elseif m.action == ACT_AIR_THROW or m.action == ACT_AIR_THROW_LAND then
|
||||
if m.actionTimer < 3 then
|
||||
m.actionTimer = 3
|
||||
set_anim_to_frame(m, 3)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function birdo_on_set_action(m)
|
||||
if m.action ~= ACT_SPIT_EGG and m.action ~= ACT_SPIT_EGG_WALK and m.action ~= ACT_SPIT_EGG_AIR then
|
||||
gCharacterStates[m.playerIndex].birdo.spitTimer = 0
|
||||
end
|
||||
if m.action == ACT_HOLD_WALKING then -- switch to custom hold action
|
||||
set_mario_action(m, ACT_BIRDO_HOLD_WALKING, 0)
|
||||
end
|
||||
end
|
||||
|
||||
local shootActs = {
|
||||
[ACT_PUNCHING] = ACT_SPIT_EGG,
|
||||
[ACT_MOVE_PUNCHING] = ACT_SPIT_EGG_WALK,
|
||||
[ACT_JUMP_KICK] = ACT_SPIT_EGG_AIR,
|
||||
}
|
||||
|
||||
function birdo_before_action(m, action, actionArg)
|
||||
if m.playerIndex ~= 0 then return end
|
||||
if shootActs[action] and m.controller.buttonDown & A_BUTTON == 0 then
|
||||
if action == ACT_PUNCHING and actionArg == 9 then return end
|
||||
local e = gCharacterStates[m.playerIndex]
|
||||
e.birdo.framesSinceShoot = 0
|
||||
if e.birdo.spitTimer == 0 then
|
||||
e.birdo.flameCharge = 0
|
||||
end
|
||||
|
||||
local canShoot = true
|
||||
local eggCount = 0
|
||||
local gIndex = network_global_index_from_local(m.playerIndex)
|
||||
local egg = obj_get_first_with_behavior_id(id_bhvBirdoEgg)
|
||||
while egg do
|
||||
if egg.oAction == 0 and egg.oHeldState == HELD_FREE and egg.globalPlayerIndex == gIndex then
|
||||
eggCount = eggCount + 1
|
||||
if eggCount >= 3 then -- max of 3 eggs/fireballs per player
|
||||
canShoot = false
|
||||
break
|
||||
end
|
||||
end
|
||||
egg = obj_get_next_with_same_behavior_id(egg)
|
||||
end
|
||||
|
||||
if m.action ~= ACT_SPIT_EGG or e.birdo.spitTimer == 0 or canShoot then
|
||||
m.marioObj.header.gfx.animInfo.animFrame = 0
|
||||
return shootActs[action]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function birdo_on_interact(m, o, intType)
|
||||
local e = gCharacterStates[m.playerIndex]
|
||||
if intType == INTERACT_GRABBABLE and e.birdo.framesSinceShoot == 0 and e.birdo.flameCharge == 0 and (m.action == ACT_SPIT_EGG or m.action == ACT_SPIT_EGG_WALK) and o.oInteractionSubtype & INT_SUBTYPE_NOT_GRABBABLE == 0 then
|
||||
set_mario_action(m, ACT_MOVE_PUNCHING, 1)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
function birdo_before_phys_step(m)
|
||||
local hScale = 1.0
|
||||
local vScale = 1.0
|
||||
|
||||
-- faster ground movement and slower, floaty air movement
|
||||
if (m.action & ACT_FLAG_MOVING) ~= 0 and m.action ~= ACT_BUBBLED then
|
||||
hScale = hScale * 1.12 -- not as fast as toad
|
||||
elseif m.action & ACT_FLAG_AIR ~= 0 then
|
||||
hScale = hScale * 0.94
|
||||
if m.vel.y < 0 then
|
||||
vScale = vScale * 0.98
|
||||
end
|
||||
end
|
||||
|
||||
m.vel.x = m.vel.x * hScale
|
||||
m.vel.y = m.vel.y * vScale
|
||||
m.vel.z = m.vel.z * hScale
|
||||
end
|
||||
|
||||
-- allow shooting in first person
|
||||
function birdo_before_update(m)
|
||||
if m.action == ACT_FIRST_PERSON and m.controller.buttonPressed & B_BUTTON ~= 0 then
|
||||
local e = gCharacterStates[m.playerIndex]
|
||||
e.birdo.framesSinceShoot = 0
|
||||
if e.birdo.spitTimer == 0 then
|
||||
e.birdo.flameCharge = 0
|
||||
end
|
||||
m.controller.buttonPressed = m.controller.buttonPressed & ~B_BUTTON
|
||||
end
|
||||
end
|
||||
|
||||
-- interactions for birdo's egg/fireball
|
||||
function birdo_egg_interaction(o, egg)
|
||||
if egg.oBehParams ~= 0 and obj_has_behavior_id(o, id_bhvMrBlizzard) ~= 0 then
|
||||
o.oFaceAngleRoll = 0x3000
|
||||
o.oMrBlizzardHeldObj = nil
|
||||
o.prevObj = o.oMrBlizzardHeldObj
|
||||
o.oAction = MR_BLIZZARD_ACT_DEATH
|
||||
o.oMrBlizzardDizziness = 0
|
||||
o.oMrBlizzardChangeInDizziness = 0
|
||||
o.oTimer = 30
|
||||
return true
|
||||
end
|
||||
|
||||
if egg.oBehParams ~= 0 and obj_has_behavior_id(o, id_bhvBowser) ~= 0 then
|
||||
if o.oAction ~= 4 and o.oAction ~= 5 and o.oAction ~= 6 and o.oAction ~= 12 and o.oAction ~= 19 and o.oAction ~= 20 and math.abs(o.oVelY) <= 2 then
|
||||
o.oAction = 1
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
if o.oInteractType == INTERACT_BULLY then
|
||||
o.oBullyLastNetworkPlayerIndex = egg.globalPlayerIndex
|
||||
o.oForwardVel = (egg.oBehParams ~= 0 and 50) or 25
|
||||
o.oMoveAngleYaw = egg.oMoveAngleYaw
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- prevent player interaction with Birdo's egg if player interaction is not pvp (owner still interacts)
|
||||
---@param m MarioState
|
||||
---@param o Object
|
||||
---@param type integer
|
||||
function player_egg_allow_interact(m, o, type)
|
||||
if obj_has_behavior_id(o, id_bhvBirdoEgg) ~= 0 then
|
||||
local m2 = gMarioStates[network_local_index_from_global(o.globalPlayerIndex)]
|
||||
if m.playerIndex ~= m2.playerIndex and gServerSettings.playerInteractions ~= PLAYER_INTERACTIONS_PVP then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
hook_event(HOOK_ALLOW_INTERACT, player_egg_allow_interact)
|
||||
|
||||
-- returns true if this object can be hit by birdo's fireball
|
||||
function birdo_fire_is_targettable(o, egg)
|
||||
if o.oInteractType == INTERACT_PLAYER then
|
||||
local m = gMarioStates[o.oBehParams - 1]
|
||||
if (not m) or is_player_active(m) == 0 then return false end
|
||||
local gIndex = network_global_index_from_local(m.playerIndex)
|
||||
return (gServerSettings.playerInteractions == PLAYER_INTERACTIONS_PVP) and (egg.globalPlayerIndex ~= gIndex)
|
||||
end
|
||||
|
||||
return (obj_has_behavior_id(o, id_bhvMrBlizzard) ~= 0 or obj_has_behavior_id(o, id_bhvBowser) ~= 0
|
||||
or o.oInteractType == INTERACT_BULLY or o.oInteractType == INTERACT_BREAKABLE or obj_is_attackable(o))
|
||||
end
|
||||
|
||||
hook_mario_action(ACT_BIRDO_HOLD_WALKING, act_birdo_hold_walking)
|
||||
hook_mario_action(ACT_SPIT_EGG, act_spit_egg)
|
||||
hook_mario_action(ACT_SPIT_EGG_AIR, act_spit_egg_air)
|
||||
hook_mario_action(ACT_SPIT_EGG_WALK, act_spit_egg_walk)
|
||||
|
||||
-- Fix object shadows getting messed up. Base coop bug
|
||||
---@param o Object
|
||||
function on_obj_load(o)
|
||||
o.header.gfx.disableAutomaticShadowPos = false
|
||||
o.header.gfx.shadowInvisible = false
|
||||
end
|
||||
hook_event(HOOK_ON_OBJECT_LOAD, on_obj_load)
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
-------------------
|
||||
-- Daisy Moveset --
|
||||
-------------------
|
||||
|
||||
if not charSelect then return end
|
||||
|
||||
local midairJumpActs = {
|
||||
[ACT_JUMP] = true,
|
||||
[ACT_DOUBLE_JUMP] = true,
|
||||
[ACT_TRIPLE_JUMP] = true,
|
||||
[ACT_LONG_JUMP] = true,
|
||||
[ACT_BACKFLIP] = true,
|
||||
[ACT_SIDE_FLIP] = true,
|
||||
[ACT_WALL_KICK_AIR] = true,
|
||||
}
|
||||
|
||||
_G.ACT_MIDAIR_JUMP = allocate_mario_action(ACT_GROUP_AIRBORNE | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION | ACT_FLAG_MOVING)
|
||||
|
||||
--- @param m MarioState
|
||||
local function act_midair_jump(m)
|
||||
-- apply movement when using action
|
||||
common_air_action_step(m, ACT_JUMP_LAND, CHAR_ANIM_BEND_KNESS_RIDING_SHELL, AIR_STEP_NONE)
|
||||
|
||||
-- setup when action starts (vertical speed and voiceline)
|
||||
if m.actionTimer == 0 then
|
||||
m.vel.y = m.forwardVel * 0.3 + 40
|
||||
m.forwardVel = m.forwardVel * 0.7
|
||||
play_character_sound(m, CHAR_SOUND_HELLO)
|
||||
end
|
||||
|
||||
set_mario_particle_flags(m, PARTICLE_LEAF, 0)
|
||||
|
||||
-- avoid issue with flying and then make the hover end after 2 secs or when stopping holding the button
|
||||
if m.prevAction ~= ACT_TRIPLE_JUMP and (m.flags & MARIO_WING_CAP) ~= 0 then
|
||||
if m.actionTimer >= 10 or (m.controller.buttonDown & A_BUTTON) == 0 then
|
||||
set_mario_action(m, ACT_FREEFALL, 0)
|
||||
end
|
||||
else
|
||||
if m.actionTimer >= 10 or (m.controller.buttonDown & A_BUTTON) == 0 then
|
||||
set_mario_action(m, ACT_FREEFALL, 0)
|
||||
end
|
||||
end
|
||||
|
||||
-- increment the action timer to make the hover stop
|
||||
m.actionTimer = m.actionTimer + 1
|
||||
end
|
||||
|
||||
--- @param m MarioState
|
||||
function daisy_update(m)
|
||||
if (m.input & INPUT_A_PRESSED) ~= 0 and m.vel.y < 10 and m.prevAction ~= ACT_MIDAIR_JUMP and midairJumpActs[m.action] then
|
||||
set_mario_action(m, ACT_MIDAIR_JUMP, 0)
|
||||
end
|
||||
end
|
||||
|
||||
hook_mario_action(ACT_MIDAIR_JUMP, act_midair_jump)
|
||||
|
|
@ -1,955 +0,0 @@
|
|||
-------------------------
|
||||
-- Donkey Kong Moveset --
|
||||
-------------------------
|
||||
|
||||
if not charSelect then return end
|
||||
|
||||
local DONKEY_KONG_ROLL_SPEED = 60
|
||||
local DONKEY_KONG_ROLL_DECAY_PERCENT = 0.98
|
||||
local DONKEY_KONG_ROLL_DECAY_TIME = 10
|
||||
local DONKEY_KONG_ROLL_STARTUP = 4
|
||||
local DONKEY_KONG_ROLL_END = 25
|
||||
local DONKEY_KONG_SLIP_TIME = 20
|
||||
local DONKEY_KONG_SLIDE_TIME = 40
|
||||
|
||||
----------------
|
||||
-- DK Gravity --
|
||||
----------------
|
||||
|
||||
--- @param m MarioState
|
||||
--- @param wall Surface
|
||||
--- @param intendedPos Vec3f
|
||||
--- @param nextPos Vec3f
|
||||
--- @return integer
|
||||
--- Checks ledge grab for donkey kong
|
||||
local function donkey_kong_check_ledge_grab(m, wall, intendedPos, nextPos)
|
||||
if not m then return 0 end
|
||||
local ledgeFloor
|
||||
local ledgePos = gVec3fZero()
|
||||
local displacementX
|
||||
local displacementZ
|
||||
|
||||
if m.vel.y > 0 then
|
||||
return 0
|
||||
end
|
||||
|
||||
displacementX = nextPos.x - intendedPos.x
|
||||
displacementZ = nextPos.z - intendedPos.z
|
||||
|
||||
-- Only ledge grab if the wall displaced Mario in the opposite direction of
|
||||
-- his velocity.
|
||||
if displacementX * m.vel.x + displacementZ * m.vel.z > 0.0 then
|
||||
return 0
|
||||
end
|
||||
|
||||
--! Since the search for floors starts at y + m.marioObj.hitboxHeight (160.0f), we will sometimes grab
|
||||
-- a higher ledge than expected (glitchy ledge grab)
|
||||
ledgePos.x = nextPos.x - wall.normal.x * 60.0
|
||||
ledgePos.z = nextPos.z - wall.normal.z * 60.0
|
||||
ledgePos.y, ledgeFloor = find_floor(ledgePos.x, nextPos.y + m.marioObj.hitboxHeight, ledgePos.z)
|
||||
if not ledgeFloor then return 0 end
|
||||
|
||||
if gLevelValues.fixCollisionBugs ~= 0 and gLevelValues.fixCollisionBugsFalseLedgeGrab ~= 0 then
|
||||
-- fix false ledge grabs
|
||||
if (not ledgeFloor or ledgeFloor.normal.y < 0.90630779) then
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
if ledgePos.y - nextPos.y <= 100.0 then
|
||||
return 0
|
||||
end
|
||||
|
||||
vec3f_copy(m.pos, ledgePos)
|
||||
m.floor = ledgeFloor
|
||||
m.floorHeight = ledgePos.y
|
||||
|
||||
m.floorAngle = atan2s(ledgeFloor.normal.z, ledgeFloor.normal.x)
|
||||
|
||||
m.faceAngle.x = 0
|
||||
m.faceAngle.y = atan2s(wall.normal.z, wall.normal.x) + 0x8000
|
||||
return 1
|
||||
end
|
||||
|
||||
--- Turns a WallCollisionData object into a table
|
||||
--- @param wcd WallCollisionData
|
||||
--- @return table
|
||||
local function wcd_to_table(wcd)
|
||||
return {
|
||||
x = wcd.x, -- number
|
||||
y = wcd.y, -- number
|
||||
z = wcd.z, -- number
|
||||
offsetY = wcd.offsetY, -- number
|
||||
radius = wcd.radius, -- number
|
||||
unused = wcd.unused, -- integer
|
||||
numWalls = wcd.numWalls, -- integer
|
||||
walls = {
|
||||
wcd.walls[1],
|
||||
wcd.walls[2],
|
||||
wcd.walls[3],
|
||||
wcd.walls[4]
|
||||
} , -- Surface[]
|
||||
normalAddition = {
|
||||
x = wcd.normalAddition.x,
|
||||
y = wcd.normalAddition.y,
|
||||
z = wcd.normalAddition.z,
|
||||
}, -- Vec3f
|
||||
normalCount = wcd.normalCount, -- integer
|
||||
}
|
||||
end
|
||||
|
||||
--- Fills a WallCollisionData object from a table
|
||||
--- @param wcd WallCollisionData
|
||||
--- @param t table
|
||||
local function table_to_wcd(wcd, t)
|
||||
wcd.x = t.x
|
||||
wcd.y = t.y
|
||||
wcd.z = t.z
|
||||
wcd.offsetY = t.offsetY
|
||||
wcd.radius = t.radius
|
||||
wcd.unused = t.unused
|
||||
wcd.numWalls = t.numWalls
|
||||
wcd.walls[1] = t.walls[1]
|
||||
wcd.walls[2] = t.walls[2]
|
||||
wcd.walls[3] = t.walls[3]
|
||||
wcd.walls[4] = t.walls[4]
|
||||
wcd.normalAddition.x = t.normalAddition.x
|
||||
wcd.normalAddition.y = t.normalAddition.y
|
||||
wcd.normalAddition.z = t.normalAddition.z
|
||||
wcd.normalCount = t.normalCount
|
||||
end
|
||||
|
||||
--- @param m MarioState
|
||||
--- @param intendedPos Vec3f
|
||||
--- @param stepArg integer
|
||||
--- @return integer
|
||||
--- Performs an air quarter step for donkey kong
|
||||
local function perform_donkey_kong_air_quarter_step(m, intendedPos, stepArg)
|
||||
if not m then return 0 end
|
||||
local wallDYaw
|
||||
local nextPos = gVec3fZero()
|
||||
local ceil
|
||||
local floor
|
||||
local ceilHeight
|
||||
local floorHeight
|
||||
local waterLevel
|
||||
local tempWcd
|
||||
|
||||
vec3f_copy(nextPos, intendedPos)
|
||||
|
||||
-- Important note:
|
||||
-- The WallCollisionData pointer is always the same, meaning it cannot be used for both upperWcd and lowerWcd
|
||||
-- Fortunately, it's read-write, so we can turn it into a table for the Lua part of the function and
|
||||
-- turn it back into a WallCollisionData object for the C function calls
|
||||
|
||||
tempWcd = collision_get_temp_wall_collision_data()
|
||||
resolve_and_return_wall_collisions_data(nextPos, 150.0, 50.0, tempWcd)
|
||||
local upperWcd = wcd_to_table(tempWcd)
|
||||
|
||||
tempWcd = collision_get_temp_wall_collision_data()
|
||||
resolve_and_return_wall_collisions_data(nextPos, 30.0, 50.0, tempWcd)
|
||||
local lowerWcd = wcd_to_table(tempWcd)
|
||||
|
||||
floorHeight, floor = find_floor(nextPos.x, nextPos.y, nextPos.z)
|
||||
ceilHeight, ceil = vec3f_mario_ceil(nextPos, floorHeight)
|
||||
waterLevel = find_water_level(nextPos.x, nextPos.z)
|
||||
|
||||
m.wall = nil
|
||||
|
||||
--! The water pseudo floor is not referenced when your intended qstep is
|
||||
-- out of bounds, so it won't detect you as landing.
|
||||
|
||||
if not floor then
|
||||
if nextPos.y <= m.floorHeight then
|
||||
m.pos.y = m.floorHeight
|
||||
return AIR_STEP_LANDED
|
||||
end
|
||||
|
||||
m.pos.y = nextPos.y
|
||||
if gServerSettings.bouncyLevelBounds ~= BOUNCY_LEVEL_BOUNDS_OFF then
|
||||
m.faceAngle.y = m.faceAngle.y + 0x8000
|
||||
mario_set_forward_vel(m, gServerSettings.bouncyLevelBounds == BOUNCY_LEVEL_BOUNDS_ON_CAP and math.clamp(1.5 * m.forwardVel, -500, 500) or 1.5 * m.forwardVel)
|
||||
end
|
||||
return AIR_STEP_HIT_WALL
|
||||
end
|
||||
|
||||
if (m.action & ACT_FLAG_RIDING_SHELL) ~= 0 and floorHeight < waterLevel then
|
||||
local allowForceAction = TRIPLET_BUTTERFLY_ACT_ACTIVATE
|
||||
if allowForceAction then
|
||||
floorHeight = waterLevel
|
||||
floor = get_water_surface_pseudo_floor()
|
||||
floor.originOffset = floorHeight
|
||||
end
|
||||
end
|
||||
|
||||
--! This check uses f32, but findFloor uses short (overflow jumps)
|
||||
if nextPos.y <= floorHeight then
|
||||
if ceilHeight - floorHeight > m.marioObj.hitboxHeight then
|
||||
m.pos.x = nextPos.x
|
||||
m.pos.z = nextPos.z
|
||||
m.floor = floor
|
||||
m.floorHeight = floorHeight
|
||||
end
|
||||
|
||||
--! When ceilHeight - floorHeight <= m->marioObj->hitboxHeight (160.0f), the step result says that
|
||||
-- Mario landed, but his movement is cancelled and his referenced floor
|
||||
-- isn't updated (pedro spots)
|
||||
m.pos.y = floorHeight
|
||||
return AIR_STEP_LANDED
|
||||
end
|
||||
|
||||
if nextPos.y + m.marioObj.hitboxHeight > ceilHeight then
|
||||
if m.vel.y >= 0.0 then
|
||||
m.vel.y = 0.0
|
||||
|
||||
--! Uses referenced ceiling instead of ceil (ceiling hang upwarp)
|
||||
if (stepArg and (stepArg & AIR_STEP_CHECK_HANG) ~= 0) and m.ceil and m.ceil.type == SURFACE_HANGABLE then
|
||||
return AIR_STEP_GRABBED_CEILING
|
||||
end
|
||||
|
||||
return AIR_STEP_NONE
|
||||
end
|
||||
|
||||
if nextPos.y <= m.floorHeight then
|
||||
m.pos.y = m.floorHeight
|
||||
return AIR_STEP_LANDED
|
||||
end
|
||||
|
||||
m.pos.y = nextPos.y
|
||||
return AIR_STEP_HIT_WALL
|
||||
end
|
||||
|
||||
--! When the wall is not completely vertical or there is a slight wall
|
||||
-- misalignment, you can activate these conditions in unexpected situations
|
||||
if (stepArg and (stepArg & AIR_STEP_CHECK_LEDGE_GRAB) ~= 0) and upperWcd.numWalls == 0 and lowerWcd.numWalls > 0 then
|
||||
for i = 1, lowerWcd.numWalls do
|
||||
if gLevelValues.fixCollisionBugs == 0 then
|
||||
i = lowerWcd.numWalls
|
||||
end
|
||||
local wall = lowerWcd.walls[i]
|
||||
if donkey_kong_check_ledge_grab(m, wall, intendedPos, nextPos) ~= 0 then
|
||||
return AIR_STEP_GRABBED_LEDGE
|
||||
end
|
||||
end
|
||||
|
||||
vec3f_copy(m.pos, nextPos)
|
||||
m.floor = floor
|
||||
m.floorHeight = floorHeight
|
||||
return AIR_STEP_NONE
|
||||
end
|
||||
|
||||
vec3f_copy(m.pos, nextPos)
|
||||
m.floor = floor
|
||||
m.floorHeight = floorHeight
|
||||
|
||||
if upperWcd.numWalls > 0 then
|
||||
table_to_wcd(tempWcd, upperWcd)
|
||||
mario_update_wall(m, tempWcd)
|
||||
upperWcd = wcd_to_table(tempWcd)
|
||||
|
||||
for i = 1, upperWcd.numWalls do
|
||||
if gLevelValues.fixCollisionBugs == 0 then
|
||||
i = upperWcd.numWalls
|
||||
end
|
||||
|
||||
local wall = upperWcd.walls[i]
|
||||
wallDYaw = atan2s(wall.normal.z, wall.normal.x) - m.faceAngle.y
|
||||
|
||||
if wall.type == SURFACE_BURNING then
|
||||
m.wall = wall
|
||||
return AIR_STEP_HIT_LAVA_WALL
|
||||
end
|
||||
|
||||
if wallDYaw < -0x6000 or wallDYaw > 0x6000 then
|
||||
m.wall = wall
|
||||
m.flags = m.flags | MARIO_UNKNOWN_30
|
||||
return AIR_STEP_HIT_WALL
|
||||
end
|
||||
end
|
||||
elseif lowerWcd.numWalls > 0 then
|
||||
table_to_wcd(tempWcd, lowerWcd)
|
||||
mario_update_wall(m, tempWcd)
|
||||
lowerWcd = wcd_to_table(tempWcd)
|
||||
|
||||
for i = 1, lowerWcd.numWalls do
|
||||
if gLevelValues.fixCollisionBugs == 0 then
|
||||
i = lowerWcd.numWalls
|
||||
end
|
||||
|
||||
local wall = lowerWcd.walls[i]
|
||||
wallDYaw = atan2s(wall.normal.z, wall.normal.x) - m.faceAngle.y
|
||||
|
||||
if wall.type == SURFACE_BURNING then
|
||||
m.wall = wall
|
||||
return AIR_STEP_HIT_LAVA_WALL
|
||||
end
|
||||
|
||||
if wallDYaw < -0x6000 or wallDYaw > 0x6000 then
|
||||
m.wall = wall
|
||||
m.flags = m.flags | MARIO_UNKNOWN_30
|
||||
return AIR_STEP_HIT_WALL
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return AIR_STEP_NONE
|
||||
end
|
||||
|
||||
--- @param m MarioState
|
||||
--- Applies twirl gravity to donkey kong
|
||||
local function apply_donkey_kong_twirl_gravity(m)
|
||||
if not m then return end
|
||||
local terminalVelocity
|
||||
local heaviness = 1.0
|
||||
|
||||
if m.angleVel.y > 1024 then
|
||||
heaviness = 1024.0 / m.angleVel.y
|
||||
end
|
||||
|
||||
terminalVelocity = -75.0 * heaviness
|
||||
|
||||
m.vel.y = m.vel.y - 4.0 * heaviness
|
||||
if m.vel.y < terminalVelocity then
|
||||
m.vel.y = terminalVelocity
|
||||
end
|
||||
end
|
||||
|
||||
--- @param m MarioState
|
||||
--- @return integer
|
||||
--- Checks if gravity should be strengthen for donkey kong jump ascent
|
||||
local function should_strengthen_gravity_for_donkey_kong_jump_ascent(m)
|
||||
if not m then return 0 end
|
||||
if m.flags & MARIO_UNKNOWN_08 == 0 then
|
||||
return 0
|
||||
end
|
||||
|
||||
if m.action & ACT_FLAG_INTANGIBLE ~= 0 or m.action & ACT_FLAG_INVULNERABLE ~= 0 then
|
||||
return 0
|
||||
end
|
||||
|
||||
if m.input & INPUT_A_DOWN == 0 and m.vel.y > 20.0 then
|
||||
return m.action & ACT_FLAG_CONTROL_JUMP_HEIGHT ~= 0 and 1 or 0
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
--- @param m MarioState
|
||||
--- Applies gravity to donkey kong
|
||||
local function apply_donkey_kong_gravity(m)
|
||||
if m.action == ACT_TWIRLING and m.vel.y < 0.0 then
|
||||
apply_donkey_kong_twirl_gravity(m)
|
||||
elseif m.action == ACT_SHOT_FROM_CANNON then
|
||||
m.vel.y = math.max(-75, m.vel.y - 1)
|
||||
elseif m.action == ACT_LONG_JUMP or m.action == ACT_SLIDE_KICK or m.action == ACT_BBH_ENTER_SPIN then
|
||||
m.vel.y = math.max(-75, m.vel.y - 3.0)
|
||||
elseif m.action == ACT_LAVA_BOOST or m.action == ACT_FALL_AFTER_STAR_GRAB then
|
||||
m.vel.y = math.max(-65, m.vel.y - 4.8)
|
||||
elseif m.action == ACT_GETTING_BLOWN then
|
||||
m.vel.y = math.max(-75, m.vel.y - (1.5 * m.unkC4))
|
||||
elseif should_strengthen_gravity_for_donkey_kong_jump_ascent(m) ~= 0 then
|
||||
m.vel.y = m.vel.y / 4.0
|
||||
elseif m.action & ACT_FLAG_METAL_WATER ~= 0 then
|
||||
m.vel.y = math.max(-16, m.vel.y - 2.4)
|
||||
elseif 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 - 3.0
|
||||
if m.vel.y < -37.5 then
|
||||
m.vel.y = math.min(-37.5, m.vel.y + 4)
|
||||
end
|
||||
else
|
||||
if m.vel.y < 0 then
|
||||
m.vel.y = math.max(-75, m.vel.y - 6)
|
||||
else
|
||||
m.vel.y = math.max(-75, m.vel.y - 4.25)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param m MarioState
|
||||
--- Applies vertical wind to donkey kong
|
||||
local function apply_donkey_kong_vertical_wind(m)
|
||||
if not m then return end
|
||||
local maxVelY
|
||||
local offsetY
|
||||
if m.action ~= ACT_GROUND_POUND then
|
||||
offsetY = m.pos.y - -1500.0
|
||||
|
||||
if m.floor and m.floor.type == SURFACE_VERTICAL_WIND and -3000.0 < offsetY and offsetY < 2000.0 then
|
||||
if offsetY >= 0.0 then
|
||||
maxVelY = 10000.0 / (offsetY + 200.0)
|
||||
else
|
||||
maxVelY = 50.0
|
||||
end
|
||||
|
||||
if m.vel.y < maxVelY then
|
||||
m.vel.y = (m.vel.y + maxVelY / 6.0) -- Bit stronger so DK doesn't fall through
|
||||
if m.vel.y > maxVelY then
|
||||
m.vel.y = maxVelY
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- @param m MarioState
|
||||
--- @param stepArg integer
|
||||
--- @return integer
|
||||
--- Performs an air step for donkey kong
|
||||
local function perform_donkey_kong_air_step(m, stepArg)
|
||||
local intendedPos = gVec3fZero()
|
||||
local quarterStepResult
|
||||
local stepResult = AIR_STEP_NONE
|
||||
|
||||
m.wall = nil
|
||||
|
||||
for i = 0, 3 do
|
||||
local step = gVec3fZero()
|
||||
step = {
|
||||
x = m.vel.x / 4.0,
|
||||
y = m.vel.y / 4.0,
|
||||
z = m.vel.z / 4.0,
|
||||
}
|
||||
|
||||
intendedPos.x = m.pos.x + step.x
|
||||
intendedPos.y = m.pos.y + step.y
|
||||
intendedPos.z = m.pos.z + step.z
|
||||
|
||||
vec3f_normalize(step)
|
||||
set_find_wall_direction(step, true, true)
|
||||
|
||||
quarterStepResult = perform_donkey_kong_air_quarter_step(m, intendedPos, stepArg)
|
||||
set_find_wall_direction(step, false, false)
|
||||
|
||||
--! On one qf, hit OOB/ceil/wall to store the 2 return value, and continue
|
||||
-- getting 0s until your last qf. Graze a wall on your last qf, and it will
|
||||
-- return the stored 2 with a sharply angled reference wall. (some gwks)
|
||||
|
||||
if (quarterStepResult ~= AIR_STEP_NONE) then
|
||||
stepResult = quarterStepResult
|
||||
end
|
||||
|
||||
if (quarterStepResult == AIR_STEP_LANDED or quarterStepResult == AIR_STEP_GRABBED_LEDGE
|
||||
or quarterStepResult == AIR_STEP_GRABBED_CEILING
|
||||
or quarterStepResult == AIR_STEP_HIT_LAVA_WALL) then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if (m.vel.y >= 0.0) then
|
||||
m.peakHeight = m.pos.y
|
||||
end
|
||||
|
||||
m.terrainSoundAddend = mario_get_terrain_sound_addend(m)
|
||||
|
||||
-- Start climbing
|
||||
if m.wall ~= nil and m.action ~= ACT_DONKEY_CLIMB and m.prevAction ~= ACT_DONKEY_CLIMB
|
||||
and (m.action & ACT_FLAG_INVULNERABLE == 0) and stepResult ~= AIR_STEP_HIT_LAVA_WALL
|
||||
and m.input & INPUT_A_DOWN ~= 0 and m.heldObj == nil then
|
||||
local wallangle = atan2s(m.wallNormal.z, m.wallNormal.x) + 0x8000
|
||||
-- Only grab wall if within certain angle of the wall
|
||||
if abs_angle_diff(wallangle, m.faceAngle.y) < 0x3000 then
|
||||
set_mario_action(m, ACT_DONKEY_CLIMB, 0)
|
||||
if stepResult == AIR_STEP_HIT_WALL then return 0 end
|
||||
return stepResult
|
||||
end
|
||||
end
|
||||
|
||||
if (m.action ~= ACT_FLYING and m.action ~= ACT_BUBBLED) then
|
||||
apply_donkey_kong_gravity(m)
|
||||
end
|
||||
apply_donkey_kong_vertical_wind(m)
|
||||
|
||||
vec3f_copy(m.marioObj.header.gfx.pos, m.pos)
|
||||
vec3s_set(m.marioObj.header.gfx.angle, 0, m.faceAngle.y, 0)
|
||||
|
||||
return stepResult
|
||||
end
|
||||
|
||||
function donkey_kong_before_phys_step(m, stepType, stepArg)
|
||||
if stepType == STEP_TYPE_GROUND then
|
||||
-- return perform_donkey_kong_ground_step(m) -- TBA
|
||||
elseif stepType == STEP_TYPE_AIR then
|
||||
return perform_donkey_kong_air_step(m, stepArg)
|
||||
elseif stepType == STEP_TYPE_WATER then
|
||||
-- return perform_donkey_kong_water_step(m) -- TBA
|
||||
elseif stepType == STEP_TYPE_HANG then
|
||||
-- return perform_donkey_kong_hanging_step(m) -- TBA
|
||||
end
|
||||
end
|
||||
|
||||
function donkey_kong_before_action(m, action, actionArg)
|
||||
if (action == ACT_DIVE or action == ACT_MOVE_PUNCHING) and m.action & ACT_FLAG_AIR == 0 and m.input & INPUT_A_DOWN == 0 and m.forwardVel >= 20 then
|
||||
m.vel.y = 20
|
||||
m.faceAngle.x = 0
|
||||
return ACT_DONKEY_KONG_ROLL
|
||||
elseif (action == ACT_PUNCHING and actionArg == 9) then
|
||||
return ACT_DONKEY_KONG_POUND
|
||||
end
|
||||
end
|
||||
|
||||
function donkey_kong_on_interact(m, o, type, value)
|
||||
-- allow donkey kong to grab objects with the roll
|
||||
if type == INTERACT_GRABBABLE and m.action == ACT_DONKEY_KONG_ROLL then
|
||||
if ((o.oInteractionSubtype & INT_SUBTYPE_NOT_GRABBABLE) == 0) then
|
||||
m.interactObj = o
|
||||
m.input = m.input | INPUT_INTERACT_OBJ_GRABBABLE
|
||||
if (o.oSyncID ~= 0) then network_send_object(o, false) end
|
||||
return 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function on_attack_object(m, o, interaction)
|
||||
-- speed up when hitting enemies with roll
|
||||
if (m.action == ACT_DONKEY_KONG_ROLL or m.action == ACT_DONKEY_KONG_ROLL_AIR) and (interaction & INT_FAST_ATTACK_OR_SHELL ~= 0) then
|
||||
if o.oInteractType == INTERACT_BULLY then
|
||||
mario_set_forward_vel(m, -25)
|
||||
m.actionTimer = DONKEY_KONG_ROLL_DECAY_TIME
|
||||
m.actionArg = 1
|
||||
else
|
||||
local newForwardVel = math.min(m.forwardVel * 1.1, 70)
|
||||
mario_set_forward_vel(m, newForwardVel)
|
||||
m.actionTimer = 0
|
||||
m.actionArg = 0
|
||||
end
|
||||
end
|
||||
|
||||
-- Bounce code
|
||||
if (CT_DONKEY_KONG ~= _G.charSelect.character_get_current_number(m.playerIndex)) then return end
|
||||
if (_G.charSelect.get_options_status(6) ~= 0) then
|
||||
if (interaction == INT_HIT_FROM_ABOVE and m.framesSinceA < 5) then
|
||||
m.actionTimer = 0
|
||||
if (m.action == ACT_DONKEY_KONG_BOUNCE) then
|
||||
set_mario_action(m, ACT_DONKEY_KONG_BOUNCE, m.actionArg + 1)
|
||||
else
|
||||
set_mario_action(m, ACT_DONKEY_KONG_BOUNCE, 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
hook_event(HOOK_ON_ATTACK_OBJECT, on_attack_object)
|
||||
|
||||
_G.ACT_DONKEY_KONG_ROLL = allocate_mario_action(ACT_GROUP_MOVING | ACT_FLAG_ATTACKING | ACT_FLAG_MOVING)
|
||||
_G.ACT_DONKEY_KONG_ROLL_AIR = allocate_mario_action(ACT_GROUP_AIRBORNE | ACT_FLAG_ATTACKING | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
|
||||
_G.ACT_DONKEY_KONG_POUND = allocate_mario_action(ACT_GROUP_STATIONARY | ACT_FLAG_ATTACKING)
|
||||
_G.ACT_DONKEY_KONG_POUND_HIT = allocate_mario_action(ACT_GROUP_STATIONARY | ACT_FLAG_ATTACKING)
|
||||
_G.ACT_DONKEY_KONG_BOUNCE = (ACT_GROUP_AIRBORNE | ACT_FLAG_MOVING | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
|
||||
|
||||
---------------
|
||||
-- DK Bounce --
|
||||
---------------
|
||||
|
||||
--- SwagSkeleton95
|
||||
--- Allows the player to bounce across enemies with well-timed A presses. Spawns coins when chained across multiple enemies. Credit to baconator2558 for the vast majority of this code.
|
||||
--- action
|
||||
|
||||
local bounceSounds = {
|
||||
audio_sample_load("z_sfx_dk_bounce1.ogg"),
|
||||
audio_sample_load("z_sfx_dk_bounce2.ogg"),
|
||||
audio_sample_load("z_sfx_dk_bounce3.ogg")
|
||||
}
|
||||
|
||||
local coinObj = nil
|
||||
|
||||
function act_dk_bounce(m)
|
||||
if (m.actionTimer == 0) then
|
||||
set_character_animation(m, CHAR_ANIM_FORWARD_SPINNING)
|
||||
set_anim_to_frame(m, 0)
|
||||
m.forwardVel = 0
|
||||
m.vel.x = 0
|
||||
m.vel.y = 80
|
||||
play_character_sound(m, CHAR_SOUND_YAHOO_WAHA_YIPPEE)
|
||||
m.vel.z = 0
|
||||
m.slideVelX = 0
|
||||
m.slideVelZ = 0
|
||||
m.faceAngle.y = m.intendedYaw
|
||||
if (m.actionArg >= 3) then
|
||||
coinObj = spawn_non_sync_object(id_bhvBlueCoinJumping, E_MODEL_SPARKLES, m.pos.x, m.pos.y, m.pos.z, nil)
|
||||
end
|
||||
audio_sample_play(bounceSounds[math.min(m.actionArg,3)], m.pos, 0.5)
|
||||
-- plays a random sound from a table ('bounceSounds') of 3 sound files.
|
||||
-- I didn't include them here because I ripped them straight from DKCR myself
|
||||
-- and I'm under the impression that this mod mainly uses self-made sound effects
|
||||
set_mario_particle_flags(m, PARTICLE_HORIZONTAL_STAR, 0)
|
||||
end
|
||||
|
||||
if (m.actionTimer >= 1 and coinObj ~= nil) then
|
||||
coinObj.oPosX = m.pos.x
|
||||
coinObj.oPosY = m.pos.y
|
||||
coinObj.oPosZ = m.pos.z
|
||||
interact_coin(m, INTERACT_COIN, coinObj)
|
||||
coinObj = nil
|
||||
end
|
||||
|
||||
if (m.actionTimer > 5 and m.marioObj.header.gfx.animInfo.animID == CHAR_ANIM_FORWARD_SPINNING) then
|
||||
set_character_animation(m, CHAR_ANIM_TRIPLE_JUMP)
|
||||
set_anim_to_frame(m, 21)
|
||||
end
|
||||
|
||||
m.forwardVel = math.min(m.forwardVel, 95)
|
||||
|
||||
update_air_without_turn(m)
|
||||
if (m.actionTimer > 20) then
|
||||
update_air_without_turn(m)
|
||||
end
|
||||
|
||||
if (m.vel.y < 10) then
|
||||
update_air_without_turn(m)
|
||||
if (m.vel.y < -10) then
|
||||
update_air_without_turn(m)
|
||||
update_air_without_turn(m)
|
||||
update_air_without_turn(m)
|
||||
update_air_without_turn(m)
|
||||
update_air_without_turn(m)
|
||||
end
|
||||
end
|
||||
|
||||
local stepResult = perform_air_step(m, AIR_STEP_CHECK_HANG | AIR_STEP_CHECK_LEDGE_GRAB)
|
||||
|
||||
if (stepResult == AIR_STEP_LANDED) then
|
||||
set_character_animation(m, CHAR_ANIM_FORWARD_SPINNING)
|
||||
set_anim_to_frame(m, 0)
|
||||
return set_mario_action(m, ACT_DOUBLE_JUMP_LAND, 0)
|
||||
elseif (stepResult == AIR_STEP_GRABBED_LEDGE) then
|
||||
set_character_animation(m, CHAR_ANIM_IDLE_ON_LEDGE)
|
||||
return drop_and_set_mario_action(m, ACT_LEDGE_GRAB, 0)
|
||||
elseif (stepResult == AIR_STEP_GRABBED_CEILING) then
|
||||
return set_mario_action(m, ACT_START_HANGING, 0)
|
||||
end
|
||||
|
||||
m.faceAngle.y = approach_s16_symmetric(m.faceAngle.y, m.intendedYaw, (abs_angle_diff(m.faceAngle.y, m.intendedYaw) / (25 * m.actionTimer + 1)) + 750)
|
||||
update_air_without_turn(m)
|
||||
m.actionTimer = m.actionTimer + 1
|
||||
if (check_kick_or_dive_in_air(m) ~= 0) then
|
||||
return 1
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
hook_mario_action(ACT_DONKEY_KONG_BOUNCE, act_dk_bounce, INT_HIT_FROM_ABOVE)
|
||||
|
||||
--- Roll
|
||||
|
||||
---@param m MarioState
|
||||
local function act_donkey_kong_roll(m)
|
||||
if (not m) then return 0 end
|
||||
|
||||
local isSliding = (mario_floor_is_slippery(m)) ~= 0
|
||||
if isSliding then
|
||||
if update_sliding(m, 4) ~= 0 or m.actionState == 0 then
|
||||
m.faceAngle.x = 0
|
||||
return set_mario_action(m, ACT_DECELERATING, 0)
|
||||
end
|
||||
end
|
||||
|
||||
if mario_check_object_grab(m) ~= 0 then
|
||||
m.faceAngle.x = 0
|
||||
set_character_animation(m, CHAR_ANIM_FIRST_PUNCH)
|
||||
set_anim_to_frame(m, 2)
|
||||
return 1
|
||||
end
|
||||
|
||||
if (m.input & INPUT_A_PRESSED) ~= 0 then
|
||||
m.faceAngle.x = 0
|
||||
m.marioObj.header.gfx.angle.x = m.faceAngle.x
|
||||
local result = set_jumping_action(m, ACT_JUMP, 0)
|
||||
if not isSliding then
|
||||
m.forwardVel = m.forwardVel / 0.8 - 5 -- conserve all jump momentum minus 5
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local doSpinAnim = true
|
||||
m.actionTimer = m.actionTimer + 1
|
||||
|
||||
set_character_animation(m, CHAR_ANIM_START_CROUCHING)
|
||||
if m.actionState == 0 then
|
||||
doSpinAnim = false
|
||||
local newForwardVel = m.forwardVel
|
||||
newForwardVel = DONKEY_KONG_ROLL_SPEED * (m.actionTimer / DONKEY_KONG_ROLL_STARTUP)
|
||||
if m.actionTimer >= DONKEY_KONG_ROLL_STARTUP then
|
||||
newForwardVel = DONKEY_KONG_ROLL_SPEED
|
||||
m.actionState = 1
|
||||
end
|
||||
mario_set_forward_vel(m, newForwardVel)
|
||||
elseif m.actionTimer >= DONKEY_KONG_ROLL_DECAY_TIME and not isSliding then
|
||||
-- slow down after a time
|
||||
local newForwardVel = m.forwardVel
|
||||
newForwardVel = newForwardVel * DONKEY_KONG_ROLL_DECAY_PERCENT
|
||||
mario_set_forward_vel(m, newForwardVel)
|
||||
end
|
||||
|
||||
-- influence direction slightly
|
||||
m.marioObj.oMoveAngleYaw = m.faceAngle.y
|
||||
cur_obj_rotate_yaw_toward(m.intendedYaw, 0x100)
|
||||
m.faceAngle.y = m.marioObj.oMoveAngleYaw
|
||||
|
||||
local result = perform_ground_step(m)
|
||||
if result == GROUND_STEP_LEFT_GROUND then
|
||||
if m.actionState == 0 then
|
||||
mario_set_forward_vel(m, DONKEY_KONG_ROLL_SPEED)
|
||||
end
|
||||
return set_mario_action(m, ACT_DONKEY_KONG_ROLL_AIR, 0)
|
||||
elseif result == GROUND_STEP_HIT_WALL then
|
||||
if (m.wall or gServerSettings.bouncyLevelBounds == BOUNCY_LEVEL_BOUNDS_OFF) then
|
||||
m.faceAngle.x = 0
|
||||
set_mario_particle_flags(m, PARTICLE_VERTICAL_STAR, 0)
|
||||
slide_bonk(m, ACT_GROUND_BONK, ACT_WALKING)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if doSpinAnim then
|
||||
local prevFaceAngleX = m.faceAngle.x
|
||||
m.faceAngle.x = m.faceAngle.x + 0x60 * m.forwardVel
|
||||
m.marioObj.header.gfx.angle.x = m.faceAngle.x
|
||||
m.marioObj.header.gfx.pos.y = m.marioObj.header.gfx.pos.y + 50
|
||||
if prevFaceAngleX <= 0 and m.faceAngle.x > 0 then
|
||||
play_sound(SOUND_ACTION_SPIN, m.marioObj.header.gfx.cameraToObject)
|
||||
end
|
||||
end
|
||||
|
||||
-- end roll
|
||||
if m.actionTimer > DONKEY_KONG_ROLL_END then
|
||||
m.faceAngle.x = 0
|
||||
return set_mario_action(m, ACT_WALKING, 0)
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
hook_mario_action(ACT_DONKEY_KONG_ROLL, { every_frame = act_donkey_kong_roll }, INT_FAST_ATTACK_OR_SHELL)
|
||||
|
||||
---@param m MarioState
|
||||
local function act_donkey_kong_roll_air(m)
|
||||
if (not m) then return 0 end
|
||||
|
||||
if (m.input & INPUT_A_PRESSED) ~= 0 then
|
||||
m.terrainSoundAddend = 0
|
||||
m.faceAngle.x = 0
|
||||
m.marioObj.header.gfx.angle.x = m.faceAngle.x
|
||||
local result = set_mario_action(m, ACT_JUMP, 0)
|
||||
m.forwardVel = m.forwardVel / 0.8 - 5 -- conserve all jump momentum minus 5
|
||||
return result
|
||||
end
|
||||
|
||||
m.actionTimer = m.actionTimer + 1
|
||||
|
||||
-- influence direction slightly
|
||||
m.marioObj.oMoveAngleYaw = m.faceAngle.y
|
||||
cur_obj_rotate_yaw_toward(m.intendedYaw, 0x100)
|
||||
m.faceAngle.y = m.marioObj.oMoveAngleYaw
|
||||
mario_set_forward_vel(m, m.forwardVel)
|
||||
|
||||
local result = perform_air_step(m, AIR_STEP_CHECK_LEDGE_GRAB)
|
||||
if result == AIR_STEP_LANDED then
|
||||
if (check_fall_damage_or_get_stuck(m, ACT_HARD_BACKWARD_GROUND_KB) == 0) then
|
||||
set_mario_action(m, ACT_DONKEY_KONG_ROLL, 0)
|
||||
m.actionState = 1
|
||||
return 1
|
||||
end
|
||||
elseif result == AIR_STEP_HIT_WALL then
|
||||
if (m.wall or gServerSettings.bouncyLevelBounds == BOUNCY_LEVEL_BOUNDS_OFF) then
|
||||
mario_bonk_reflection(m, 1)
|
||||
if (m.vel.y > 0) then m.vel.y = 0 end
|
||||
|
||||
set_mario_particle_flags(m, PARTICLE_VERTICAL_STAR, 0)
|
||||
drop_and_set_mario_action(m, ACT_BACKWARD_AIR_KB, 0)
|
||||
return 1
|
||||
end
|
||||
elseif result == AIR_STEP_HIT_LAVA_WALL then
|
||||
lava_boost_on_wall(m)
|
||||
return 1
|
||||
end
|
||||
|
||||
local prevFaceAngleX = m.faceAngle.x
|
||||
m.faceAngle.x = m.faceAngle.x + 0x60 * m.forwardVel
|
||||
m.marioObj.header.gfx.angle.x = m.faceAngle.x
|
||||
m.marioObj.header.gfx.pos.y = m.marioObj.header.gfx.pos.y + 50
|
||||
if prevFaceAngleX <= 0 and m.faceAngle.x > 0 then
|
||||
play_sound(SOUND_ACTION_SPIN, m.marioObj.header.gfx.cameraToObject)
|
||||
end
|
||||
|
||||
if m.actionTimer > DONKEY_KONG_ROLL_END then
|
||||
m.faceAngle.x = 0
|
||||
return set_mario_action(m, ACT_FREEFALL, 0)
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
hook_mario_action(ACT_DONKEY_KONG_ROLL_AIR, { every_frame = act_donkey_kong_roll_air }, INT_FAST_ATTACK_OR_SHELL)
|
||||
|
||||
local function act_donkey_kong_pound(m)
|
||||
if (not m) then return 0 end
|
||||
|
||||
mario_set_forward_vel(m, 0)
|
||||
if (mario_floor_is_slippery(m)) ~= 0 then
|
||||
return set_mario_action(m, ACT_BEGIN_SLIDING, 0)
|
||||
end
|
||||
|
||||
if (m.input & INPUT_A_PRESSED) ~= 0 then
|
||||
local result = set_jumping_action(m, ACT_JUMP, 0)
|
||||
return result
|
||||
elseif (m.input & INPUT_B_PRESSED) ~= 0 and m.actionTimer ~= 0 then
|
||||
m.actionState = 1
|
||||
end
|
||||
|
||||
m.actionTimer = m.actionTimer + 1
|
||||
if m.actionTimer == 1 then
|
||||
play_mario_heavy_landing_sound(m, SOUND_ACTION_TERRAIN_HEAVY_LANDING)
|
||||
|
||||
-- Spawn particles at hand that hit ground
|
||||
local pos = {x = 0, y = 0, z = 0}
|
||||
if m.marioObj.header.gfx.animInfo.animFrame >= 8 then
|
||||
get_mario_anim_part_pos(m, MARIO_ANIM_PART_RIGHT_HAND, pos)
|
||||
else
|
||||
get_mario_anim_part_pos(m, MARIO_ANIM_PART_LEFT_HAND, pos)
|
||||
end
|
||||
pos.y = m.pos.y -- always appear on ground
|
||||
spawn_non_sync_object(id_bhvHorStarParticleSpawner, E_MODEL_NONE, pos.x, pos.y, pos.z, nil)
|
||||
spawn_non_sync_object(id_bhvMistCircParticleSpawner, E_MODEL_NONE, pos.x, pos.y, pos.z, nil)
|
||||
|
||||
m.action = ACT_DONKEY_KONG_POUND_HIT
|
||||
m.marioObj.hitboxRadius = 100 -- larger hitbox
|
||||
elseif m.action == ACT_DONKEY_KONG_POUND_HIT then
|
||||
m.action = ACT_DONKEY_KONG_POUND
|
||||
m.marioObj.hitboxRadius = 37 -- reset hitbox
|
||||
elseif m.actionTimer >= 8 then
|
||||
if m.actionState ~= 0 then
|
||||
-- pound again
|
||||
m.actionTimer = 0
|
||||
m.actionState = 0
|
||||
elseif m.input & INPUT_Z_DOWN ~= 0 then
|
||||
set_mario_action(m, ACT_START_CROUCHING, 0)
|
||||
else
|
||||
set_mario_action(m, ACT_IDLE, 0)
|
||||
end
|
||||
end
|
||||
|
||||
--set_character_anim_with_accel(m, CHAR_ANIM_PLACE_LIGHT_OBJ, 0x20000)
|
||||
-- 28 anim frames in 16 frames
|
||||
if m.marioObj.header.gfx.animInfo.animFrame > 15 and m.actionTimer == 0 then
|
||||
--djui_chat_message_create(tostring(m.marioObj.header.gfx.animInfo.animFrame))
|
||||
set_anim_to_frame(m, 0)
|
||||
end
|
||||
play_custom_anim(m, "donkey_ground_slap", 0x10000 * 28 // 16)
|
||||
--[[set_anim_to_frame(m, m.marioObj.header.gfx.animInfo.animFrame)
|
||||
if m.controller.buttonPressed & L_TRIG ~= 0 then
|
||||
set_anim_to_frame(m, m.marioObj.header.gfx.animInfo.animFrame + 1)
|
||||
end]]
|
||||
local result = perform_ground_step(m)
|
||||
if result == GROUND_STEP_LEFT_GROUND then
|
||||
return set_mario_action(m, ACT_FREEFALL, 0)
|
||||
end
|
||||
end
|
||||
hook_mario_action(ACT_DONKEY_KONG_POUND, { every_frame = act_donkey_kong_pound })
|
||||
|
||||
hook_mario_action(ACT_DONKEY_KONG_POUND_HIT, { every_frame = act_donkey_kong_pound }, INT_GROUND_POUND) -- same action but with ground pound interaction
|
||||
|
||||
-----------------------
|
||||
--- Donkey Climbing ---
|
||||
--- -------------------
|
||||
|
||||
DK_ANIM_CLIMBING = 'donkey_custom_climbing'
|
||||
|
||||
ACT_DONKEY_CLIMB = allocate_mario_action(ACT_FLAG_AIR | ACT_GROUP_AIRBORNE)
|
||||
|
||||
-- Climbing ability action
|
||||
--- @param m MarioState
|
||||
function act_donkey_climb(m)
|
||||
--No wall, no climb
|
||||
if m.wall == nil then
|
||||
set_mario_action(m, ACT_TRIPLE_JUMP, 0)
|
||||
mario_set_forward_vel(m, 10)
|
||||
return true
|
||||
|
||||
--Press A to jump off
|
||||
elseif (m.input & INPUT_A_PRESSED) ~= 0 then
|
||||
set_mario_action(m, ACT_JUMP, 0)
|
||||
m.faceAngle.y = m.faceAngle.y - 0x8000
|
||||
mario_set_forward_vel(m, 20)
|
||||
return true
|
||||
|
||||
--Press Z to just fall off
|
||||
elseif (m.input & INPUT_Z_PRESSED) ~= 0 then
|
||||
m.input = m.input &~ INPUT_Z_PRESSED
|
||||
play_character_sound(m, CHAR_SOUND_UH)
|
||||
|
||||
mario_set_forward_vel(m, -8)
|
||||
return set_mario_action(m, ACT_FREEFALL, 0)
|
||||
end
|
||||
|
||||
--Woah!
|
||||
if m.actionTimer == 0 then
|
||||
play_character_sound(m, CHAR_SOUND_WHOA)
|
||||
end
|
||||
|
||||
local climbAnimSpeed = m.intendedMag
|
||||
local wallangle = atan2s(m.wallNormal.z, m.wallNormal.x) + 0x8000
|
||||
local transwall
|
||||
if m.actionTimer >= 4 then
|
||||
--Face beside wall and move around it
|
||||
m.faceAngle.y = wallangle - 0x4000
|
||||
if m.actionTimer <= DONKEY_KONG_SLIP_TIME then
|
||||
mario_set_forward_vel(m, m.controller.stickX/3)
|
||||
m.vel.y = m.controller.stickY/3
|
||||
elseif m.actionTimer <= DONKEY_KONG_SLIDE_TIME then -- Slip on wall after some time
|
||||
climbAnimSpeed = 32
|
||||
m.vel.y = 0
|
||||
else
|
||||
climbAnimSpeed = 0
|
||||
m.vel.y = m.vel.y + 8 -- counteract gravity
|
||||
end
|
||||
|
||||
--Perform air step
|
||||
local air_step = perform_air_step(m, 0)
|
||||
transwall = m.wall
|
||||
if air_step == AIR_STEP_LANDED then
|
||||
return set_mario_action(m, ACT_FREEFALL_LAND, 0)
|
||||
end
|
||||
end
|
||||
|
||||
--Face directly towards wall to make sure we're latched on
|
||||
m.faceAngle.y = wallangle
|
||||
mario_set_forward_vel(m, 1)
|
||||
if m.actionTimer <= DONKEY_KONG_SLIP_TIME then
|
||||
m.vel.y = 0
|
||||
elseif m.actionTimer <= DONKEY_KONG_SLIDE_TIME then
|
||||
m.vel.y = 5
|
||||
end
|
||||
|
||||
--Perform air step
|
||||
air_step = perform_air_step(m, 0)
|
||||
if air_step == AIR_STEP_LANDED then
|
||||
return set_mario_action(m, ACT_FREEFALL_LAND, 0)
|
||||
elseif m.wall == nil then
|
||||
if transwall == nil then
|
||||
set_mario_action(m, ACT_TRIPLE_JUMP, 0)
|
||||
mario_set_forward_vel(m, 10)
|
||||
return true
|
||||
else
|
||||
m.wall = transwall
|
||||
end
|
||||
end
|
||||
|
||||
--Climbing animation
|
||||
play_custom_anim(m, "donkey_custom_climbing", climbAnimSpeed * 0x3000)
|
||||
if m.actionTimer < 8 or climbAnimSpeed == 0 then
|
||||
set_anim_to_frame(m, 0)
|
||||
else
|
||||
m.particleFlags = m.particleFlags | PARTICLE_DUST
|
||||
|
||||
m.terrainSoundAddend = SOUND_TERRAIN_SAND << 16
|
||||
play_step_sound(m, 26, 79)
|
||||
end
|
||||
local inward_offset = 25
|
||||
m.marioObj.header.gfx.pos.x = m.marioObj.header.gfx.pos.x + inward_offset * sins(m.faceAngle.y)
|
||||
m.marioObj.header.gfx.pos.z = m.marioObj.header.gfx.pos.z + inward_offset * coss(m.faceAngle.y)
|
||||
|
||||
m.actionTimer = m.actionTimer + 1
|
||||
end
|
||||
hook_mario_action(ACT_DONKEY_CLIMB, {every_frame = act_donkey_climb, gravity = function() end})
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,59 +0,0 @@
|
|||
-------------------
|
||||
-- Peach Moveset --
|
||||
-------------------
|
||||
|
||||
if not charSelect then return end
|
||||
|
||||
local floatActs = {
|
||||
[ACT_JUMP] = true,
|
||||
[ACT_DOUBLE_JUMP] = true,
|
||||
[ACT_TRIPLE_JUMP] = true,
|
||||
[ACT_LONG_JUMP] = true,
|
||||
[ACT_BACKFLIP] = true,
|
||||
[ACT_SIDE_FLIP] = true,
|
||||
[ACT_WALL_KICK_AIR] = true,
|
||||
}
|
||||
|
||||
_G.ACT_FLOAT = allocate_mario_action(ACT_GROUP_AIRBORNE | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION | ACT_FLAG_MOVING)
|
||||
|
||||
--- @param m MarioState
|
||||
local function act_float(m)
|
||||
-- apply movement when using action
|
||||
common_air_action_step(m, ACT_JUMP_LAND, CHAR_ANIM_BEND_KNESS_RIDING_SHELL, AIR_STEP_NONE)
|
||||
|
||||
-- setup when action starts (horizontal speed and voiceline)
|
||||
if m.actionTimer == 0 then
|
||||
play_character_sound(m, CHAR_SOUND_HELLO)
|
||||
end
|
||||
|
||||
if m.forwardVel > 20 then
|
||||
m.forwardVel = m.forwardVel - 0.5
|
||||
end
|
||||
|
||||
-- Slowly decend
|
||||
m.vel.y = -1
|
||||
set_mario_particle_flags(m, PARTICLE_SPARKLES, 0)
|
||||
|
||||
-- avoid issue with flying and then make the hover end after 2 secs or when stopping holding the button
|
||||
if m.prevAction ~= ACT_TRIPLE_JUMP and (m.flags & MARIO_WING_CAP) ~= 0 then
|
||||
if m.actionTimer >= 50 or (m.controller.buttonDown & A_BUTTON) == 0 then
|
||||
set_mario_action(m, ACT_FREEFALL, 0)
|
||||
end
|
||||
else
|
||||
if m.actionTimer >= 50 or (m.controller.buttonDown & A_BUTTON) == 0 then
|
||||
set_mario_action(m, ACT_FREEFALL, 0)
|
||||
end
|
||||
end
|
||||
|
||||
-- increment the action timer to make the hover stop
|
||||
m.actionTimer = m.actionTimer + 1
|
||||
end
|
||||
|
||||
--- @param m MarioState
|
||||
function peach_update(m)
|
||||
if (m.input & INPUT_A_DOWN) ~= 0 and m.vel.y < -10 and m.prevAction ~= ACT_FLOAT and floatActs[m.action] then
|
||||
set_mario_action(m, ACT_FLOAT, 0)
|
||||
end
|
||||
end
|
||||
|
||||
hook_mario_action(ACT_FLOAT, act_float)
|
||||
|
|
@ -1,203 +0,0 @@
|
|||
----------------------
|
||||
-- Rosalina Moveset --
|
||||
----------------------
|
||||
|
||||
if not charSelect then return end
|
||||
|
||||
_G.ACT_JUMP_TWIRL = allocate_mario_action(ACT_GROUP_AIRBORNE | ACT_FLAG_AIR | ACT_FLAG_ATTACKING)
|
||||
E_MODEL_TWIRL_EFFECT = smlua_model_util_get_id("spin_attack_geo")
|
||||
|
||||
---@param o Object
|
||||
local function bhv_spin_attack_init(o)
|
||||
o.oFlags = OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE -- Allows you to change the position and angle
|
||||
end
|
||||
|
||||
---@param o Object
|
||||
local function bhv_spin_attack_loop(o)
|
||||
|
||||
-- Retrieves the Mario state corresponding to its global index
|
||||
local m = gMarioStates[network_local_index_from_global(o.globalPlayerIndex)]
|
||||
if m == nil or m.marioObj == nil then
|
||||
obj_mark_for_deletion(o)
|
||||
return
|
||||
end
|
||||
|
||||
o.parentObj = m.marioObj -- Sets the Mario object as its parent
|
||||
cur_obj_set_pos_relative_to_parent(0, 20, 0) -- Makes it move to its parent's position
|
||||
|
||||
o.oFaceAngleYaw = o.oFaceAngleYaw + 0x2000 -- Rotates it
|
||||
|
||||
if m.action ~= ACT_JUMP_TWIRL or o.oTimer > 15 then -- Deletes itself once the action changes
|
||||
obj_mark_for_deletion(o)
|
||||
end
|
||||
end
|
||||
|
||||
local id_bhvTwirlEffect = hook_behavior(nil, OBJ_LIST_GENACTOR, true, bhv_spin_attack_init, bhv_spin_attack_loop,
|
||||
"bhvRosalinaTwirlEffect")
|
||||
|
||||
-- Spinable actions, these are actions you can spin out of that don't normally allow a kick/dive
|
||||
local extraSpinActs = {
|
||||
[ACT_LONG_JUMP] = true,
|
||||
[ACT_BACKFLIP] = true,
|
||||
}
|
||||
|
||||
-- Spin overridable actions, these are overriden instantly
|
||||
local spinOverrides = {
|
||||
[ACT_PUNCHING] = true,
|
||||
[ACT_MOVE_PUNCHING] = true,
|
||||
[ACT_JUMP_KICK] = true,
|
||||
[ACT_DIVE] = true
|
||||
}
|
||||
|
||||
local ROSALINA_SOUND_SPIN = audio_sample_load("z_sfx_rosalina_spinattack.ogg") -- Load audio sample
|
||||
|
||||
---@param m MarioState
|
||||
function act_jump_twirl(m)
|
||||
local e = gCharacterStates[m.playerIndex]
|
||||
|
||||
if m.actionTimer >= 15 then
|
||||
return set_mario_action(m, ACT_FREEFALL, 0) -- End the action
|
||||
end
|
||||
|
||||
if m.actionTimer == 0 then
|
||||
m.marioObj.header.gfx.animInfo.animID = -1
|
||||
play_character_sound(m, CHAR_SOUND_HELLO) -- Plays the character sound
|
||||
audio_sample_play(ROSALINA_SOUND_SPIN, m.pos, 1) -- Plays the spin sound sample
|
||||
m.particleFlags = m.particleFlags | ACTIVE_PARTICLE_SPARKLES -- Spawns sparkle particles
|
||||
|
||||
if e.rosalina.canSpin then
|
||||
m.vel.y = 30 -- Initial upward velocity
|
||||
e.rosalina.canSpin = false
|
||||
|
||||
-- Spawn the spin effect
|
||||
if m.playerIndex == 0 then
|
||||
spawn_sync_object(id_bhvTwirlEffect, E_MODEL_TWIRL_EFFECT, m.pos.x, m.pos.y, m.pos.z, function(o)
|
||||
o.globalPlayerIndex = m.marioObj.globalPlayerIndex
|
||||
end)
|
||||
end
|
||||
else
|
||||
m.vel.y = math.max(m.vel.y, 0)
|
||||
end
|
||||
m.marioObj.hitboxRadius = 100 -- Damage hitbox
|
||||
else
|
||||
m.marioObj.hitboxRadius = 37 -- Reset the hitbox after initial hit
|
||||
end
|
||||
|
||||
common_air_action_step(m, ACT_FREEFALL_LAND, CHAR_ANIM_BEND_KNESS_RIDING_SHELL, AIR_STEP_NONE)
|
||||
|
||||
m.marioBodyState.handState = MARIO_HAND_PEACE_SIGN -- Hand State
|
||||
|
||||
-- Increments the action timer
|
||||
m.actionTimer = m.actionTimer + 1
|
||||
end
|
||||
|
||||
---@param m MarioState
|
||||
---@param o Object
|
||||
---@param intType InteractionType
|
||||
function rosalina_allow_interact(m, o, intType)
|
||||
local e = gCharacterStates[m.playerIndex]
|
||||
if m.action == ACT_JUMP_TWIRL and intType == INTERACT_GRABBABLE and o.oInteractionSubtype & INT_SUBTYPE_NOT_GRABBABLE == 0 then
|
||||
local angleTo = mario_obj_angle_to_object(m, o)
|
||||
if (o.oInteractionSubtype & INT_SUBTYPE_GRABS_MARIO ~= 0 or obj_has_behavior_id(o, id_bhvBowser) ~= 0) then -- heavy grab objects
|
||||
if m.pos.y - m.floorHeight < 100 and abs_angle_diff(m.faceAngle.y, angleTo) < 0x4000 then
|
||||
m.action = ACT_MOVE_PUNCHING
|
||||
m.actionArg = 1
|
||||
end
|
||||
elseif not e.rosalina.orbitObjActive then -- light grab objects
|
||||
m.usedObj = o
|
||||
e.rosalina.orbitObjActive = true
|
||||
e.rosalina.orbitObjDist = 160 - m.actionTimer * 2
|
||||
e.rosalina.orbitObjAngle = angleTo
|
||||
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param m MarioState
|
||||
function rosalina_update(m)
|
||||
local e = gCharacterStates[m.playerIndex]
|
||||
|
||||
if m.controller.buttonPressed & B_BUTTON ~= 0 and extraSpinActs[m.action] then
|
||||
return set_mario_action(m, ACT_JUMP_TWIRL, 0)
|
||||
end
|
||||
|
||||
--if m.action & ACT_FLAG_AIR == 0 and m.playerIndex == 0 then
|
||||
-- e.rosalina.canSpin = true
|
||||
--end
|
||||
|
||||
if m.action ~= ACT_JUMP_TWIRL and m.marioObj.hitboxRadius ~= 37 then
|
||||
m.marioObj.hitboxRadius = 37
|
||||
end
|
||||
|
||||
if e.rosalina.orbitObjActive then
|
||||
local o = m.usedObj
|
||||
|
||||
if not o or o.activeFlags == ACTIVE_FLAG_DEACTIVATED then
|
||||
e.rosalina.orbitObjActive = false
|
||||
o.oIntangibleTimer = 0
|
||||
|
||||
if m.playerIndex == 0 then m.usedObj = nil end
|
||||
return
|
||||
end
|
||||
|
||||
e.rosalina.orbitObjDist = e.rosalina.orbitObjDist - 6
|
||||
if e.rosalina.orbitObjDist >= 90 then
|
||||
e.rosalina.orbitObjAngle = e.rosalina.orbitObjAngle + 0x1800
|
||||
else
|
||||
e.rosalina.orbitObjAngle = approach_s16_asymptotic(e.rosalina.orbitObjAngle, m.faceAngle.y, 4)
|
||||
end
|
||||
|
||||
o.oPosX = m.pos.x + sins(e.rosalina.orbitObjAngle) * e.rosalina.orbitObjDist
|
||||
o.oPosZ = m.pos.z + coss(e.rosalina.orbitObjAngle) * e.rosalina.orbitObjDist
|
||||
o.oPosY = approach_f32_asymptotic(o.oPosY, m.pos.y + 50, 0.25)
|
||||
|
||||
obj_set_vel(o, 0, 0, 0)
|
||||
o.oForwardVel = 0
|
||||
o.oIntangibleTimer = -1
|
||||
|
||||
if m.playerIndex == 0 and e.rosalina.orbitObjDist <= 80 then
|
||||
e.rosalina.orbitObjActive = false
|
||||
o.oIntangibleTimer = 0
|
||||
|
||||
if m.action & (ACT_FLAG_INVULNERABLE | ACT_FLAG_INTANGIBLE) ~= 0 or m.action & ACT_GROUP_MASK >= ACT_GROUP_SUBMERGED then
|
||||
m.usedObj = nil
|
||||
else
|
||||
o.oIntangibleTimer = 0
|
||||
m.interactObj = o
|
||||
m.usedObj = o
|
||||
if o.oSyncID ~= 0 then network_send_object(o, true) end
|
||||
|
||||
if m.action & ACT_FLAG_AIR == 0 then
|
||||
set_mario_action(m, ACT_HOLD_IDLE, 0)
|
||||
mario_grab_used_object(m)
|
||||
else
|
||||
set_mario_action(m, ACT_HOLD_FREEFALL, 0)
|
||||
mario_grab_used_object(m)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param m MarioState
|
||||
function rosalina_before_action(m, action)
|
||||
if not action then return end
|
||||
|
||||
local e = gCharacterStates[m.playerIndex]
|
||||
|
||||
if spinOverrides[action] and m.controller.buttonDown & (Z_TRIG | A_BUTTON) == 0 and m.action ~= ACT_STEEP_JUMP then
|
||||
return ACT_JUMP_TWIRL
|
||||
end
|
||||
|
||||
if action & ACT_FLAG_AIR == 0 and not e.rosalina.canSpin then
|
||||
play_sound_with_freq_scale(SOUND_GENERAL_COIN_SPURT_EU, m.marioObj.header.gfx.cameraToObject, 1.6)
|
||||
if m.playerIndex == 0 then
|
||||
spawn_sync_object(id_bhvSparkle, E_MODEL_SPARKLES_ANIMATION, m.pos.x, m.pos.y + 200, m.pos.z,
|
||||
function(o) obj_scale(o, 0.75) end)
|
||||
end
|
||||
e.rosalina.canSpin = true
|
||||
end
|
||||
end
|
||||
|
||||
hook_mario_action(ACT_JUMP_TWIRL, act_jump_twirl, INT_KICK)
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,596 +0,0 @@
|
|||
-------------------
|
||||
-- Spike Moveset --
|
||||
-------------------
|
||||
|
||||
if not charSelect then return end
|
||||
|
||||
-----------------
|
||||
-- Spike Bombs --
|
||||
-----------------
|
||||
|
||||
_G.ACT_SPIKE_PLACE_BOMB = allocate_mario_action(ACT_GROUP_STATIONARY | ACT_FLAG_STATIONARY)
|
||||
_G.ACT_SPIKE_PLACE_BOMB_AIR = allocate_mario_action(ACT_GROUP_AIRBORNE | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
|
||||
_G.ACT_BOMB_JUMP = allocate_mario_action(ACT_GROUP_AIRBORNE | ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION)
|
||||
|
||||
---@param m MarioState
|
||||
local function act_spike_place_bomb(m)
|
||||
if (not m) then return 0 end
|
||||
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 drop_and_set_mario_action(m, ACT_FREEFALL, 0)
|
||||
end
|
||||
|
||||
m.actionTimer = m.actionTimer + 1
|
||||
if m.playerIndex == 0 and m.actionTimer == 4 then
|
||||
spike_spawn_bomb(m)
|
||||
end
|
||||
|
||||
play_character_sound_if_no_flag(m, CHAR_SOUND_PUNCH_YAH, MARIO_ACTION_SOUND_PLAYED)
|
||||
animated_stationary_ground_step(m, CHAR_ANIM_PLACE_LIGHT_OBJ, ACT_IDLE)
|
||||
set_anim_to_frame(m, m.marioObj.header.gfx.animInfo.animFrame + 2)
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
---@param m MarioState
|
||||
local function act_spike_place_bomb_air(m)
|
||||
if (not m) then return 0 end
|
||||
|
||||
if (m.actionState == 0) then
|
||||
play_character_sound_if_no_flag(m, CHAR_SOUND_PUNCH_YAH, MARIO_ACTION_SOUND_PLAYED)
|
||||
set_character_animation(m, CHAR_ANIM_PLACE_LIGHT_OBJ)
|
||||
if is_anim_past_frame(m, 10) ~= 0 then
|
||||
m.actionState = 1
|
||||
else
|
||||
set_anim_to_frame(m, m.marioObj.header.gfx.animInfo.animFrame + 2)
|
||||
end
|
||||
else
|
||||
set_character_animation(m, CHAR_ANIM_GENERAL_FALL)
|
||||
end
|
||||
|
||||
update_air_without_turn(m)
|
||||
|
||||
m.actionTimer = m.actionTimer + 1
|
||||
if m.playerIndex == 0 and m.actionTimer == 4 then
|
||||
spike_spawn_bomb(m, true)
|
||||
end
|
||||
|
||||
local result = perform_air_step(m, (m.actionState == 1 and AIR_STEP_CHECK_LEDGE_GRAB) or 0)
|
||||
if result == AIR_STEP_LANDED then
|
||||
if (check_fall_damage_or_get_stuck(m, ACT_HARD_BACKWARD_GROUND_KB) == 0) then
|
||||
set_mario_action(m, ACT_FREEFALL_LAND, 0)
|
||||
end
|
||||
elseif result == AIR_STEP_HIT_WALL then
|
||||
if (m.wall or gServerSettings.bouncyLevelBounds == BOUNCY_LEVEL_BOUNDS_OFF) then
|
||||
mario_set_forward_vel(m, 0)
|
||||
end
|
||||
elseif result == AIR_STEP_GRABBED_LEDGE then
|
||||
set_mario_action(m, ACT_LEDGE_GRAB, 0)
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
---@param m MarioState
|
||||
function spike_attempt_explode_bomb(m)
|
||||
local gIndex = network_global_index_from_local(m.playerIndex)
|
||||
local o = obj_get_first_with_behavior_id(id_bhvSpikeBomb)
|
||||
while o do
|
||||
if o.globalPlayerIndex == gIndex then
|
||||
o.oBreakableWallForce = 1
|
||||
network_send_object(o, false)
|
||||
return true
|
||||
end
|
||||
o = obj_get_next_with_same_behavior_id(o)
|
||||
end
|
||||
|
||||
-- if invincible, prevent spawning bombs
|
||||
if m.flags & MARIO_VANISH_CAP ~= 0 or m.invincTimer ~= 0 then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
---@param m MarioState
|
||||
function spike_spawn_bomb(m, air)
|
||||
if spike_attempt_explode_bomb(m) then return end
|
||||
|
||||
local pos = gVec3fZero()
|
||||
if air then
|
||||
pos.x = m.pos.x
|
||||
pos.y = m.pos.y - 133
|
||||
pos.z = m.pos.z
|
||||
else
|
||||
pos.x = m.pos.x + 80 * sins(m.faceAngle.y)
|
||||
pos.y = m.pos.y
|
||||
pos.z = m.pos.z + 80 * coss(m.faceAngle.y)
|
||||
end
|
||||
spawn_sync_object(id_bhvSpikeBomb, E_MODEL_SPIKE_BOMB, pos.x, pos.y, pos.z, function(o)
|
||||
o.oVelY = 0
|
||||
o.oForwardVel = m.forwardVel
|
||||
o.globalPlayerIndex = network_global_index_from_local(m.playerIndex)
|
||||
end)
|
||||
end
|
||||
|
||||
-- note that other players can end up in this action
|
||||
---@param m MarioState
|
||||
local function act_bomb_jump(m)
|
||||
update_air_without_turn(m)
|
||||
|
||||
if m.actionState == 0 then
|
||||
play_character_sound_if_no_flag(m, CHAR_SOUND_YAHOO_WAHA_YIPPEE, MARIO_ACTION_SOUND_PLAYED)
|
||||
set_character_animation(m, CHAR_ANIM_FORWARD_SPINNING)
|
||||
|
||||
if m.health <= 0xFF then
|
||||
m.actionState = 1
|
||||
end
|
||||
else
|
||||
m.peakHeight = m.pos.y + 10000 -- force falling sound
|
||||
play_far_fall_sound(m)
|
||||
set_character_animation(m, CHAR_ANIM_AIRBORNE_ON_STOMACH)
|
||||
end
|
||||
|
||||
local result = perform_air_step(m, (m.actionState == 0 and AIR_STEP_CHECK_HANG | AIR_STEP_CHECK_LEDGE_GRAB) or 0)
|
||||
if result == AIR_STEP_LANDED then
|
||||
if m.actionState ~= 0 then
|
||||
set_mario_action(m, ACT_HARD_FORWARD_GROUND_KB, 0)
|
||||
elseif (check_fall_damage_or_get_stuck(m, ACT_HARD_FORWARD_GROUND_KB) == 0) then
|
||||
set_mario_action(m, ACT_TRIPLE_JUMP_LAND, 0)
|
||||
end
|
||||
elseif result == AIR_STEP_HIT_WALL then
|
||||
if (m.wall or gServerSettings.bouncyLevelBounds == BOUNCY_LEVEL_BOUNDS_OFF) then
|
||||
mario_set_forward_vel(m, 0)
|
||||
end
|
||||
elseif result == AIR_STEP_GRABBED_LEDGE then
|
||||
set_mario_action(m, ACT_LEDGE_GRAB, 0)
|
||||
elseif result == AIR_STEP_GRABBED_CEILING then
|
||||
set_mario_action(m, ACT_START_HANGING, 0)
|
||||
end
|
||||
|
||||
if m.actionState ~= 0 then
|
||||
m.actionTimer = m.actionTimer + 1
|
||||
m.marioObj.header.gfx.angle.x = m.actionTimer * 0x1000 - 0x4000
|
||||
m.marioObj.header.gfx.angle.y = m.faceAngle.y + m.actionTimer * 0x800
|
||||
m.marioObj.header.gfx.angle.z = m.actionTimer * 0x1200
|
||||
else
|
||||
m.actionTimer = 0
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
-- Bomb object
|
||||
|
||||
local spikeColObjLists = {
|
||||
OBJ_LIST_GENACTOR,
|
||||
OBJ_LIST_PUSHABLE,
|
||||
OBJ_LIST_SURFACE,
|
||||
OBJ_LIST_DESTRUCTIVE
|
||||
}
|
||||
|
||||
E_MODEL_SPIKE_BOMB = smlua_model_util_get_id("spike_bomb_geo")
|
||||
---@param o Object
|
||||
function bhv_spike_bomb_init(o)
|
||||
o.oFlags = (OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE | OBJ_FLAG_COMPUTE_DIST_TO_MARIO | OBJ_FLAG_HOLDABLE)
|
||||
o.oFaceAngleRoll = 0
|
||||
o.oMoveAngleRoll = 0
|
||||
o.oGravity = 2.5
|
||||
--o.oBounciness = 0
|
||||
o.oFriction = 0
|
||||
--o.oDragStrength = 0.5
|
||||
o.oBuoyancy = 1.3
|
||||
o.oWallHitboxRadius = 60
|
||||
|
||||
local hitbox = get_temp_object_hitbox()
|
||||
hitbox.interactType = INTERACT_GRABBABLE
|
||||
hitbox.hurtboxRadius = 0
|
||||
hitbox.hurtboxHeight = 0
|
||||
hitbox.downOffset = 0
|
||||
hitbox.radius = 65
|
||||
hitbox.height = 133
|
||||
hitbox.damageOrCoinValue = 0
|
||||
obj_set_hitbox(o, hitbox)
|
||||
|
||||
o.oInteractionSubtype = (INT_SUBTYPE_KICKABLE | INT_SUBTYPE_NOT_GRABBABLE)
|
||||
network_init_object(o, true, { 'globalPlayerIndex', 'oBreakableWallForce' })
|
||||
end
|
||||
|
||||
---@param o Object
|
||||
function bhv_spike_bomb_loop(o)
|
||||
local m = gMarioStates[network_local_index_from_global(o.globalPlayerIndex)]
|
||||
if is_player_active(m) == 0 or ((m.playerIndex == 0 or o.oHeldState ~= HELD_FREE) and (m.action == ACT_SPIKE_PLACE_BOMB or m.action == ACT_SPIKE_PLACE_BOMB_AIR)
|
||||
and (m.actionTimer <= 1 or m.controller.buttonPressed & B_BUTTON ~= 0)) then
|
||||
o.oBreakableWallForce = 1
|
||||
if m.playerIndex == 0 then
|
||||
network_send_object(o, false)
|
||||
end
|
||||
end
|
||||
|
||||
-- only allow us to pick up our own bombs
|
||||
-- (holding another player's bomb makes it appear using our own colors, that's literally the only reason this restriction exists)
|
||||
if m.playerIndex ~= 0 then
|
||||
o.oInteractionSubtype = o.oInteractionSubtype | INT_SUBTYPE_NOT_GRABBABLE
|
||||
else
|
||||
o.oInteractionSubtype = o.oInteractionSubtype & ~INT_SUBTYPE_NOT_GRABBABLE
|
||||
end
|
||||
|
||||
if o.oHeldState == HELD_FREE then
|
||||
cur_obj_enable_rendering()
|
||||
-- become tangible if we were untangible, but not if timer is set
|
||||
if o.oIntangibleTimer == -1 then o.oIntangibleTimer = 0 end
|
||||
|
||||
local colFlags = object_step()
|
||||
local floor = nil
|
||||
if colFlags & OBJ_COL_FLAG_GROUNDED ~= 0 then
|
||||
floor = collision_find_floor(o.oPosX, o.oPosY, o.oPosZ)
|
||||
if o.oAction == 1 or (floor == nil or floor.type == SURFACE_BURNING or floor.type == SURFACE_DEATH_PLANE or floor.type == SURFACE_VERTICAL_WIND) then
|
||||
o.oBreakableWallForce = 1
|
||||
end
|
||||
elseif colFlags & OBJ_COL_FLAG_HIT_WALL ~= 0 then
|
||||
if o.oAction == 1 then
|
||||
o.oBreakableWallForce = 1
|
||||
end
|
||||
end
|
||||
|
||||
if o.oAction == 0 and o.oTimer == 1 then
|
||||
cur_obj_play_sound_1(SOUND_AIR_BOBOMB_LIT_FUSE)
|
||||
end
|
||||
|
||||
if ((o.oInteractStatus & INT_STATUS_INTERACTED) ~= 0) then
|
||||
if ((o.oInteractStatus & INT_STATUS_MARIO_UNK1) ~= 0) then
|
||||
local player = nearest_player_to_object(o)
|
||||
if (player) then
|
||||
o.oMoveAngleYaw = player.header.gfx.angle.y
|
||||
end
|
||||
o.oForwardVel = 25.0
|
||||
o.oVelY = 30.0
|
||||
o.oFriction = 1
|
||||
cur_obj_change_action(1)
|
||||
end
|
||||
|
||||
if ((o.oInteractStatus & INT_STATUS_TOUCHED_BOB_OMB) ~= 0) then
|
||||
o.oBreakableWallForce = 1
|
||||
end
|
||||
end
|
||||
|
||||
-- object collision
|
||||
local collide = 0
|
||||
for i, list in ipairs(spikeColObjLists) do
|
||||
local o2 = obj_get_first(list)
|
||||
while o2 do
|
||||
if o ~= o2 and o2.oInteractStatus & INT_STATUS_INTERACTED == 0 and o2.oHeldState == HELD_FREE and o2.oInteractType ~= INTERACT_TEXT and ((floor and floor.object == o2) or obj_check_hitbox_overlap(o, o2)) then
|
||||
if floor == nil or floor.object ~= o2 then
|
||||
collide = 1
|
||||
end
|
||||
local didBombInteract = spike_bomb_interaction(o2, o)
|
||||
if didBombInteract then
|
||||
collide = 1
|
||||
elseif (o2.oInteractType == INTERACT_BREAKABLE or o2.oInteractType == INTERACT_GRABBABLE or obj_is_attackable(o2)) then
|
||||
o2.oInteractStatus = o2.oInteractStatus | ATTACK_FAST_ATTACK | INT_STATUS_WAS_ATTACKED |
|
||||
INT_STATUS_INTERACTED | INT_STATUS_TOUCHED_BOB_OMB
|
||||
end
|
||||
end
|
||||
o2 = obj_get_next(o2)
|
||||
end
|
||||
end
|
||||
|
||||
if o.oAction ~= 2 and (o.oBreakableWallForce ~= 0 or collide ~= 0) then
|
||||
cur_obj_change_action(2)
|
||||
end
|
||||
o.oInteractStatus = 0
|
||||
|
||||
-- explosion action
|
||||
if o.oAction == 2 then
|
||||
local SCALE_TO_BOBOMB = 3 -- explosion is this many times larger than a normal bob-omb
|
||||
obj_set_billboard(o)
|
||||
o.oGravity = 0
|
||||
o.oVelY = 0
|
||||
o.oForwardVel = 0
|
||||
if o.oInteractType ~= INTERACT_DAMAGE then
|
||||
o.oInteractType = INTERACT_DAMAGE
|
||||
obj_set_model_extended(o, E_MODEL_EXPLOSION)
|
||||
local hitbox = get_temp_object_hitbox()
|
||||
hitbox.interactType = INTERACT_DAMAGE
|
||||
hitbox.hurtboxRadius = 150 * SCALE_TO_BOBOMB
|
||||
hitbox.hurtboxHeight = 150 * SCALE_TO_BOBOMB
|
||||
hitbox.downOffset = 150 * SCALE_TO_BOBOMB
|
||||
hitbox.radius = 150 * SCALE_TO_BOBOMB
|
||||
hitbox.height = 150 * SCALE_TO_BOBOMB
|
||||
hitbox.damageOrCoinValue = 0
|
||||
obj_set_hitbox(o, hitbox)
|
||||
bhv_explosion_init()
|
||||
end
|
||||
|
||||
if m.playerIndex == 0 or gServerSettings.playerInteractions == PLAYER_INTERACTIONS_PVP then
|
||||
-- deal damage based on distance to explosion
|
||||
local dist = lateral_dist_between_objects(o, gMarioStates[0].marioObj)
|
||||
o.oDamageOrCoinValue = math.ceil(math.clamp(1 - (dist / (200 * SCALE_TO_BOBOMB)), 0, 1) * 4)
|
||||
else
|
||||
o.oDamageOrCoinValue = 0 -- deal no damage
|
||||
end
|
||||
|
||||
if o.oTimer == 9 then
|
||||
bhv_explosion_loop()
|
||||
end
|
||||
o.oOpacity = o.oOpacity - 14
|
||||
cur_obj_scale((o.oTimer / 9.0 + 1) * SCALE_TO_BOBOMB)
|
||||
o.oAnimState = o.oAnimState + 1
|
||||
end
|
||||
elseif o.oHeldState == HELD_HELD then
|
||||
cur_obj_disable_rendering_and_become_intangible(o)
|
||||
|
||||
local heldM = gMarioStates[o.heldByPlayerIndex]
|
||||
if (heldM.playerIndex == 0 and m.playerIndex ~= 0) or (o.oBreakableWallForce ~= 0 and heldM and heldM.playerIndex == 0) then
|
||||
mario_drop_held_object(heldM)
|
||||
o.oPosX, o.oPosY, o.oPosZ = heldM.pos.x, heldM.pos.y, heldM.pos.z
|
||||
end
|
||||
elseif o.oHeldState == HELD_DROPPED then
|
||||
cur_obj_change_action(0)
|
||||
o.oTimer = 1
|
||||
o.oHeldState = HELD_FREE
|
||||
o.oFaceAngleYaw = o.oMoveAngleYaw
|
||||
elseif o.oHeldState == HELD_THROWN then
|
||||
o.oForwardVel = 25.0
|
||||
o.oVelY = 30.0
|
||||
cur_obj_change_action(1)
|
||||
o.oHeldState = HELD_FREE
|
||||
o.oFaceAngleYaw = o.oMoveAngleYaw
|
||||
end
|
||||
end
|
||||
id_bhvSpikeBomb = hook_behavior(nil, OBJ_LIST_DESTRUCTIVE, true, bhv_spike_bomb_init, bhv_spike_bomb_loop, "bhvSpikeBomb")
|
||||
|
||||
-------------------
|
||||
-- Spike Hammers --
|
||||
-------------------
|
||||
|
||||
-- hammer object
|
||||
E_MODEL_SPIKE_HAMMER = smlua_model_util_get_id("spike_hammer_geo")
|
||||
---@param o Object
|
||||
function bhv_spike_hammer_init(o)
|
||||
o.oFlags = (OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE | OBJ_FLAG_COMPUTE_DIST_TO_MARIO | OBJ_FLAG_SET_FACE_ANGLE_TO_MOVE_ANGLE)
|
||||
o.oGravity = -4
|
||||
o.oBounciness = 0
|
||||
o.oFriction = 1
|
||||
o.oDragStrength = 0
|
||||
o.oBuoyancy = 0
|
||||
o.oWallHitboxRadius = 60
|
||||
cur_obj_scale(0.75)
|
||||
|
||||
local hitbox = get_temp_object_hitbox()
|
||||
hitbox.interactType = INTERACT_DAMAGE
|
||||
hitbox.hurtboxRadius = 0
|
||||
hitbox.hurtboxHeight = 0
|
||||
hitbox.downOffset = 100
|
||||
hitbox.radius = 100
|
||||
hitbox.height = 200
|
||||
hitbox.damageOrCoinValue = 2
|
||||
local prevIntangibleTimer = o.oIntangibleTimer
|
||||
obj_set_hitbox(o, hitbox)
|
||||
o.oIntangibleTimer = prevIntangibleTimer
|
||||
|
||||
network_init_object(o, true, { 'globalPlayerIndex' })
|
||||
end
|
||||
|
||||
---@param o Object
|
||||
function bhv_spike_hammer_loop(o)
|
||||
cur_obj_update_floor_and_walls()
|
||||
cur_obj_move_standard(60)
|
||||
if o.oMoveFlags & (OBJ_MOVE_HIT_WALL | OBJ_MOVE_MASK_ON_GROUND | OBJ_MOVE_UNDERWATER_ON_GROUND) ~= 0 then
|
||||
spawn_mist_particles()
|
||||
obj_mark_for_deletion(o)
|
||||
end
|
||||
|
||||
if o.oTimer == 1 then
|
||||
cur_obj_play_sound_1(SOUND_ACTION_SIDE_FLIP_UNK)
|
||||
end
|
||||
|
||||
-- Don't do damage to others unless PVP is on
|
||||
local m = gMarioStates[network_local_index_from_global(o.globalPlayerIndex)]
|
||||
if m.playerIndex ~= 0 and gServerSettings.playerInteractions ~= PLAYER_INTERACTIONS_PVP then
|
||||
o.oDamageOrCoinValue = 0
|
||||
else
|
||||
o.oDamageOrCoinValue = 2
|
||||
end
|
||||
|
||||
o.oMoveAnglePitch = o.oMoveAnglePitch + 0x1000
|
||||
|
||||
-- object collision
|
||||
local collide = 0
|
||||
for i, list in ipairs(spikeColObjLists) do
|
||||
local o2 = obj_get_first(list)
|
||||
while o2 do
|
||||
if o ~= o2 and o2.oInteractStatus & INT_STATUS_INTERACTED == 0 and o2.oHeldState == HELD_FREE and o2.oInteractType ~= INTERACT_TEXT and obj_check_hitbox_overlap(o, o2) then
|
||||
collide = 1
|
||||
local didHammerInteract = spike_hammer_interaction(o2, o)
|
||||
if (not didHammerInteract) and (o2.oInteractType == INTERACT_BREAKABLE or o2.oInteractType == INTERACT_GRABBABLE or obj_is_attackable(o2)) then
|
||||
o2.oInteractStatus = o2.oInteractStatus | ATTACK_GROUND_POUND_OR_TWIRL | INT_STATUS_WAS_ATTACKED |
|
||||
INT_STATUS_INTERACTED | INT_STATUS_TOUCHED_BOB_OMB
|
||||
end
|
||||
end
|
||||
o2 = obj_get_next(o2)
|
||||
end
|
||||
end
|
||||
if collide ~= 0 or o.oInteractStatus ~= 0 then
|
||||
spawn_mist_particles()
|
||||
obj_mark_for_deletion(o)
|
||||
end
|
||||
o.oInteractStatus = 0
|
||||
end
|
||||
id_bhvSpikeHammer = hook_behavior(nil, OBJ_LIST_DESTRUCTIVE, true, bhv_spike_hammer_init, bhv_spike_hammer_loop, "bhvSpikeHammer")
|
||||
|
||||
---@param m MarioState
|
||||
function spike_update(m)
|
||||
if m.controller.buttonPressed & B_BUTTON ~= 0 and (m.action == ACT_GROUND_POUND or (m.action == ACT_LONG_JUMP and m.controller.buttonDown & Z_TRIG ~= 0)) then
|
||||
m.vel.y = 20
|
||||
m.forwardVel = 0
|
||||
if spike_attempt_explode_bomb(m) then
|
||||
set_mario_action(m, ACT_JUMP_KICK, 0)
|
||||
else
|
||||
set_mario_action(m, ACT_SPIKE_PLACE_BOMB_AIR, 0)
|
||||
end
|
||||
end
|
||||
|
||||
-- throw hammer when punching
|
||||
if m.playerIndex == 0 and (m.action == ACT_PUNCHING or m.action == ACT_MOVE_PUNCHING)
|
||||
and m.actionArg == 1 and m.marioObj.header.gfx.animInfo.animFrame == 2 and m.heldObj == nil then
|
||||
spawn_sync_object(id_bhvSpikeHammer, E_MODEL_SPIKE_HAMMER, m.pos.x, m.pos.y + 80, m.pos.z, function(o)
|
||||
o.oVelY = 50
|
||||
o.oForwardVel = 40
|
||||
o.oMoveAngleYaw = m.faceAngle.y
|
||||
o.oMoveAnglePitch, o.oMoveAngleRoll = 0, 0
|
||||
o.oIntangibleTimer = 7
|
||||
o.globalPlayerIndex = network_global_index_from_local(m.playerIndex)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
---@param m MarioState
|
||||
---@param action integer
|
||||
function spike_before_action(m, action)
|
||||
if (action == ACT_PUNCHING or action == ACT_MOVE_PUNCHING) and m.controller.buttonDown & Z_TRIG ~= 0 then
|
||||
if not spike_attempt_explode_bomb(m) then
|
||||
return ACT_SPIKE_PLACE_BOMB
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- handle player interaction with spike's bomb
|
||||
---@param m MarioState
|
||||
---@param o Object
|
||||
---@param type integer
|
||||
---@param value boolean
|
||||
function player_bomb_interact(m, o, type, value)
|
||||
if obj_has_behavior_id(o, id_bhvSpikeBomb) ~= 0 and type == INTERACT_DAMAGE and value then
|
||||
if m.pos.y > o.oPosY and o.oDamageOrCoinValue >= 4 and m.action & ACT_FLAG_AIR ~= 0 then
|
||||
m.invincTimer = math.max(m.invincTimer, 3)
|
||||
m.faceAngle.y = m.intendedYaw
|
||||
set_mario_action(m, ACT_BOMB_JUMP, 0)
|
||||
m.vel.y = 69
|
||||
m.forwardVel = 16
|
||||
if m.playerIndex == 0 then
|
||||
o.oIntangibleTimer = 3 -- needed for arena
|
||||
end
|
||||
else
|
||||
if m.action & (ACT_FLAG_AIR | ACT_FLAG_WATER_OR_TEXT | ACT_FLAG_METAL_WATER) == 0 then
|
||||
if m.action == ACT_FORWARD_GROUND_KB or m.action == ACT_HARD_FORWARD_GROUND_KB or m.action == ACT_SOFT_FORWARD_GROUND_KB then
|
||||
set_mario_action(m, ACT_HARD_FORWARD_AIR_KB, 0)
|
||||
else
|
||||
set_mario_action(m, ACT_HARD_BACKWARD_AIR_KB, 0)
|
||||
end
|
||||
end
|
||||
|
||||
m.forwardVel = o.oDamageOrCoinValue * 10
|
||||
m.vel.y = o.oDamageOrCoinValue * 20
|
||||
end
|
||||
end
|
||||
end
|
||||
hook_event(HOOK_ON_INTERACT, player_bomb_interact)
|
||||
|
||||
-- prevent player interaction with Spike's bomb if player interaction is off (owner still interacts)
|
||||
---@param m MarioState
|
||||
---@param o Object
|
||||
---@param type integer
|
||||
function player_bomb_hammer_allow_interact(m, o, type)
|
||||
if (obj_has_behavior_id(o, id_bhvSpikeBomb) ~= 0 or obj_has_behavior_id(o, id_bhvSpikeHammer) ~= 0) and type == INTERACT_DAMAGE then
|
||||
local m2 = gMarioStates[network_local_index_from_global(o.globalPlayerIndex)]
|
||||
if m.playerIndex ~= m2.playerIndex and gServerSettings.playerInteractions == PLAYER_INTERACTIONS_NONE then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
hook_event(HOOK_ALLOW_INTERACT, player_bomb_hammer_allow_interact)
|
||||
|
||||
-- handle other object interactions with spike's bomb
|
||||
---@param o Object
|
||||
---@param bomb Object
|
||||
function spike_bomb_interaction(o, bomb)
|
||||
if obj_has_behavior_id(o, id_bhvSmallWhomp) ~= 0 then
|
||||
o.oNumLootCoins = 5
|
||||
obj_spawn_loot_yellow_coins(o, 5, 20)
|
||||
o.oAction = 8
|
||||
return true
|
||||
end
|
||||
|
||||
if obj_has_behavior_id(o, id_bhvGoomba) ~= 0 and o.oGoombaSize == 1 then
|
||||
o.oInteractStatus = o.oInteractStatus | ATTACK_GROUND_POUND_OR_TWIRL | INT_STATUS_WAS_ATTACKED |
|
||||
INT_STATUS_INTERACTED
|
||||
return true
|
||||
end
|
||||
|
||||
-- Is this too much?
|
||||
if obj_has_behavior_id(o, id_bhvThwomp) ~= 0 or obj_has_behavior_id(o, id_bhvThwomp2) ~= 0 then
|
||||
o.oNumLootCoins = 5
|
||||
obj_spawn_loot_yellow_coins(o, 5, 20)
|
||||
spawn_mist_particles_variable(0, 0, 100)
|
||||
spawn_triangle_break_particles(20, 138, 3, 4)
|
||||
cur_obj_shake_screen(SHAKE_POS_SMALL)
|
||||
create_sound_spawner(SOUND_OBJ_THWOMP)
|
||||
obj_mark_for_deletion(o)
|
||||
return true
|
||||
end
|
||||
|
||||
if obj_has_behavior_id(o, id_bhvWfBreakableWallLeft) ~= 0
|
||||
or obj_has_behavior_id(o, id_bhvWfBreakableWallRight) ~= 0 then
|
||||
o.oBreakableWallForce = 1
|
||||
return true
|
||||
end
|
||||
|
||||
if obj_has_behavior_id(o, id_bhvChuckya) ~= 0 then
|
||||
o.oAction = 2
|
||||
o.oForwardVel = 30
|
||||
o.oMoveAngleYaw = obj_angle_to_object(o, bomb) + 0x8000
|
||||
o.oVelY = 10
|
||||
o.oChuckyaUnk88 = 3 -- auto throw mario
|
||||
obj_init_animation(o, 2)
|
||||
return true
|
||||
end
|
||||
|
||||
if obj_has_behavior_id(o, id_bhvChainChomp) ~= 0 then
|
||||
o.oInteractStatus = o.oInteractStatus | ATTACK_FAST_ATTACK |
|
||||
INT_STATUS_TOUCHED_BOB_OMB | INT_STATUS_WAS_ATTACKED | INT_STATUS_INTERACTED
|
||||
return true
|
||||
end
|
||||
|
||||
if o.oInteractType == INTERACT_BULLY then
|
||||
o.oBullyLastNetworkPlayerIndex = bomb.globalPlayerIndex
|
||||
o.oForwardVel = 50
|
||||
o.oMoveAngleYaw = obj_angle_to_object(o, bomb) + 0x8000
|
||||
o.oVelY = 20
|
||||
o.oInteractStatus = o.oInteractStatus | ATTACK_FAST_ATTACK |
|
||||
INT_STATUS_TOUCHED_BOB_OMB | INT_STATUS_WAS_ATTACKED | INT_STATUS_INTERACTED
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- handle object interaction's with spike's hammer (literally just bullies and spike's objects)
|
||||
---@param o Object
|
||||
---@param hammer Object
|
||||
function spike_hammer_interaction(o, hammer)
|
||||
if o.oInteractType == INTERACT_BULLY then
|
||||
o.oBullyLastNetworkPlayerIndex = hammer.globalPlayerIndex
|
||||
o.oForwardVel = 30
|
||||
o.oMoveAngleYaw = hammer.oMoveAngleYaw
|
||||
o.oInteractStatus = o.oInteractStatus | ATTACK_FAST_ATTACK |
|
||||
INT_STATUS_TOUCHED_BOB_OMB | INT_STATUS_WAS_ATTACKED | INT_STATUS_INTERACTED
|
||||
return true
|
||||
end
|
||||
|
||||
-- prevent interaction early (since punching is grab, and failing the grab would otherwise explode the bomb)
|
||||
if obj_has_behavior_id(o, id_bhvSpikeBomb) ~= 0 and hammer.oIntangibleTimer ~= 0 then
|
||||
return true
|
||||
end
|
||||
|
||||
-- break both hammers
|
||||
if obj_has_behavior_id(o, id_bhvSpikeHammer) ~= 0 then
|
||||
o.oInteractStatus = o.oInteractStatus | INT_STATUS_INTERACTED
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
hook_mario_action(ACT_SPIKE_PLACE_BOMB, { every_frame = act_spike_place_bomb })
|
||||
hook_mario_action(ACT_SPIKE_PLACE_BOMB_AIR, { every_frame = act_spike_place_bomb_air })
|
||||
hook_mario_action(ACT_BOMB_JUMP, { every_frame = act_bomb_jump })
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
----------------------
|
||||
-- Toadette Moveset --
|
||||
----------------------
|
||||
|
||||
if not charSelect then return end
|
||||
|
||||
function toadette_before_phys_step(m)
|
||||
local hScale = 1.0
|
||||
local vScale = 1.0
|
||||
|
||||
-- faster ground movement
|
||||
if (m.action & ACT_FLAG_MOVING) ~= 0 then
|
||||
hScale = hScale * 1.05
|
||||
end
|
||||
|
||||
-- slower holding item
|
||||
if m.heldObj then
|
||||
m.vel.y = m.vel.y - 2.0
|
||||
hScale = hScale * 0.9
|
||||
if (m.action & ACT_FLAG_AIR) ~= 0 then
|
||||
hScale = hScale * 0.9
|
||||
end
|
||||
end
|
||||
|
||||
m.vel.x = m.vel.x * hScale
|
||||
m.vel.y = m.vel.y * vScale
|
||||
m.vel.z = m.vel.z * hScale
|
||||
end
|
||||
|
||||
function toadette_on_set_action(m)
|
||||
local e = gCharacterStates[m.playerIndex]
|
||||
|
||||
-- wall kick height based on how fast toadette is going
|
||||
if m.action == ACT_WALL_KICK_AIR and m.prevAction ~= ACT_HOLDING_POLE and m.prevAction ~= ACT_CLIMBING_POLE then
|
||||
m.vel.y = m.vel.y * 0.8
|
||||
m.vel.y = m.vel.y + e.toadette.averageForwardVel * 0.8
|
||||
return
|
||||
end
|
||||
|
||||
-- more distance on dive and long jump
|
||||
if m.action == ACT_DIVE or m.action == ACT_LONG_JUMP then
|
||||
m.forwardVel = m.forwardVel * 1
|
||||
end
|
||||
|
||||
-- less height on jumps
|
||||
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_STEEP_JUMP or m.action == ACT_RIDING_SHELL_JUMP or m.action == ACT_BACKFLIP or m.action == ACT_WALL_KICK_AIR or m.action == ACT_LONG_JUMP then
|
||||
m.vel.y = m.vel.y * 1
|
||||
|
||||
-- prevent from getting stuck on platform
|
||||
if m.marioObj.platform then
|
||||
m.pos.y = m.pos.y + 10
|
||||
end
|
||||
elseif m.action == ACT_SIDE_FLIP then
|
||||
m.vel.y = m.vel.y * 0.86
|
||||
|
||||
-- prevent from getting stuck on platform
|
||||
if m.marioObj.platform then
|
||||
m.pos.y = m.pos.y + 10
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function toadette_update(m)
|
||||
local e = gCharacterStates[m.playerIndex]
|
||||
|
||||
-- track average forward velocity
|
||||
if e.toadette.averageForwardVel > m.forwardVel then
|
||||
e.toadette.averageForwardVel = e.toadette.averageForwardVel * 0.93 + m.forwardVel * 0.07
|
||||
else
|
||||
e.toadette.averageForwardVel = m.forwardVel
|
||||
end
|
||||
|
||||
-- keep your momentum for a while
|
||||
if m.action == ACT_WALKING and m.forwardVel > 30 then
|
||||
mario_set_forward_vel(m, m.forwardVel + 0.8)
|
||||
end
|
||||
|
||||
-- faster flip during ground pound
|
||||
if m.action == ACT_GROUND_POUND then
|
||||
m.marioObj.header.gfx.animInfo.animAccel = 32768 * 4
|
||||
if m.actionTimer < 10 then
|
||||
m.actionTimer = m.actionTimer + 1
|
||||
end
|
||||
end
|
||||
|
||||
-- Floaty
|
||||
if m.vel.y < 0 and (m.action == ACT_JUMP or m.action == ACT_DOUBLE_JUMP or m.action == ACT_TRIPLE_JUMP or m.action == ACT_HOLD_JUMP) then
|
||||
m.vel.y = m.vel.y + 0.9
|
||||
end
|
||||
end
|
||||
|
|
@ -1,302 +0,0 @@
|
|||
-------------------------
|
||||
-- Wapeach Axe Attacks --
|
||||
-------------------------
|
||||
|
||||
if not charSelect then return end
|
||||
|
||||
_G.ACT_AXE_CHOP = allocate_mario_action(ACT_GROUP_STATIONARY | ACT_FLAG_STATIONARY)
|
||||
_G.ACT_AXE_SPIN = allocate_mario_action(ACT_GROUP_MOVING | ACT_FLAG_MOVING | ACT_FLAG_ATTACKING)
|
||||
_G.ACT_AXE_SPIN_AIR = allocate_mario_action(ACT_FLAG_ATTACKING | ACT_FLAG_AIR | ACT_GROUP_AIRBORNE)
|
||||
_G.ACT_AXE_SPIN_DIZZY = allocate_mario_action(ACT_GROUP_MOVING | ACT_FLAG_MOVING)
|
||||
|
||||
---@param o Object
|
||||
local function bhv_axe_attack_init(o)
|
||||
o.oFlags = OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE | OBJ_FLAG_SET_FACE_ANGLE_TO_MOVE_ANGLE
|
||||
|
||||
o.oDamageOrCoinValue = 2
|
||||
o.oNumLootCoins = 0
|
||||
o.oHealth = 0
|
||||
o.hitboxRadius = 60
|
||||
o.hitboxHeight = 80
|
||||
o.hurtboxRadius = 60
|
||||
o.hurtboxHeight = 80
|
||||
o.hitboxDownOffset = 0
|
||||
o.oInteractType = 0
|
||||
|
||||
cur_obj_scale(1)
|
||||
cur_obj_become_tangible()
|
||||
|
||||
network_init_object(o, true, {})
|
||||
end
|
||||
|
||||
---@param o Object
|
||||
local function bhv_axe_attack_loop(o)
|
||||
local m = gMarioStates[network_local_index_from_global(o.globalPlayerIndex)]
|
||||
|
||||
local handPos = gVec3fZero()
|
||||
if not get_mario_anim_part_pos(m, MARIO_ANIM_PART_RIGHT_HAND, handPos) then
|
||||
vec3f_copy(handPos, m.pos)
|
||||
end
|
||||
|
||||
local dist = 185.0
|
||||
|
||||
local axeDir = gVec3fZero()
|
||||
vec3f_copy(axeDir, handPos)
|
||||
vec3f_sub(axeDir, m.pos)
|
||||
vec3f_normalize(axeDir)
|
||||
vec3f_mul(axeDir, 120)
|
||||
|
||||
o.oPosX = handPos.x + sins(m.faceAngle.y) * coss(m.faceAngle.x) * dist
|
||||
o.oPosY = handPos.y - axeDir.y
|
||||
o.oPosZ = handPos.z + coss(m.faceAngle.y) * coss(m.faceAngle.x) * dist
|
||||
|
||||
obj_process_attacks(o, bhvWapeachAxeAttacks)
|
||||
|
||||
if o.oTimer == 15 then
|
||||
obj_mark_for_deletion(o)
|
||||
end
|
||||
end
|
||||
|
||||
local id_bhvAxeAttack = hook_behavior(nil, OBJ_LIST_DESTRUCTIVE, true, bhv_axe_attack_init, bhv_axe_attack_loop, "bhvWapeachAxeAttack")
|
||||
|
||||
---@param m MarioState
|
||||
local function act_axe_chop(m)
|
||||
local slope = -find_floor_slope(m, 0)
|
||||
m.faceAngle.x = slope
|
||||
m.marioObj.header.gfx.angle.x = slope
|
||||
if m.actionTimer == 0 then
|
||||
set_character_animation(m, CHAR_ANIM_BREAKDANCE)
|
||||
smlua_anim_util_set_animation(m.marioObj, 'wapeach_axechop')
|
||||
play_character_sound(m, CHAR_SOUND_YAHOO_WAHA_YIPPEE)
|
||||
m.forwardVel = 0
|
||||
end
|
||||
|
||||
--if m.actionTimer >= 14 and m.actionTimer <= 40 then m.marioBodyState.handState = 2 end
|
||||
|
||||
if m.actionTimer == 17 then
|
||||
play_sound(SOUND_OBJ_POUNDING_LOUD, m.marioObj.header.gfx.cameraToObject)
|
||||
if m.playerIndex == 0 then
|
||||
local handPos = gVec3fZero()
|
||||
if not get_mario_anim_part_pos(m, MARIO_ANIM_PART_RIGHT_HAND, handPos) then
|
||||
vec3f_copy(handPos, m.pos)
|
||||
end
|
||||
spawn_sync_object(id_bhvAxeAttack, E_MODEL_NONE, handPos.x, handPos.y + 25, handPos.z, function(o)
|
||||
o.globalPlayerIndex = m.marioObj.globalPlayerIndex
|
||||
end)
|
||||
end
|
||||
-- shakey cam if you are close enough to petey (based on local player's camera)
|
||||
if vec3f_length(m.marioObj.header.gfx.cameraToObject) < 2000 then
|
||||
set_camera_shake_from_hit(SHAKE_SMALL_DAMAGE)
|
||||
end
|
||||
end
|
||||
|
||||
if is_anim_at_end(m) ~= 0 then
|
||||
set_mario_action(m, ACT_IDLE, 0)
|
||||
end
|
||||
|
||||
mario_set_forward_vel(m, approach_f32_symmetric(m.forwardVel, 0.0, 5.0))
|
||||
|
||||
local step = perform_ground_step(m)
|
||||
|
||||
if step == GROUND_STEP_LEFT_GROUND then
|
||||
return set_mario_action(m, ACT_FREEFALL, 0)
|
||||
end
|
||||
|
||||
m.actionTimer = m.actionTimer + 1
|
||||
end
|
||||
|
||||
---@param m MarioState
|
||||
local function act_axe_spin(m)
|
||||
if m.actionTimer == 0 then
|
||||
play_character_sound(m, CHAR_SOUND_YAHOO_WAHA_YIPPEE)
|
||||
m.forwardVel = math.clamp(m.forwardVel + 21, 0, 850)
|
||||
end
|
||||
|
||||
if m.controller.buttonPressed & B_BUTTON ~= 0 then
|
||||
m.forwardVel = math.clamp(m.forwardVel + 7, 0, 850)
|
||||
end
|
||||
|
||||
play_custom_anim(m, 'wapeach_axespin', math.clamp(m.forwardVel * 0x500, 0, 0x1F000))
|
||||
set_mario_particle_flags(m, PARTICLE_DUST, 0)
|
||||
if is_anim_past_frame(m, 1) ~= 0 then
|
||||
play_sound(SOUND_ACTION_SPIN, m.marioObj.header.gfx.cameraToObject)
|
||||
end
|
||||
|
||||
apply_slope_accel(m)
|
||||
if m.intendedMag > 1 then
|
||||
m.faceAngle.y = approach_s16_symmetric(m.faceAngle.y, m.intendedYaw, 0x200)
|
||||
end
|
||||
|
||||
m.forwardVel = m.forwardVel - 1.0
|
||||
mario_set_forward_vel(m, m.forwardVel)
|
||||
|
||||
local step = perform_ground_step(m)
|
||||
if m.forwardVel < 20 and m.actionTimer >= 15 then
|
||||
return set_mario_action(m, ACT_AXE_SPIN_DIZZY, 0)
|
||||
end
|
||||
if m.forwardVel >= 100 and m.actionState == 0 then
|
||||
play_character_sound(m, CHAR_SOUND_TWIRL_BOUNCE)
|
||||
m.actionState = 1
|
||||
end
|
||||
if step == GROUND_STEP_HIT_WALL then
|
||||
set_mario_particle_flags(m, PARTICLE_TRIANGLE, 0)
|
||||
mario_bonk_reflection(m, 0)
|
||||
play_sound(SOUND_ACTION_HIT_3, m.marioObj.header.gfx.cameraToObject)
|
||||
|
||||
return set_mario_action(m, ACT_AXE_SPIN_DIZZY, 0)
|
||||
end
|
||||
if step == GROUND_STEP_LEFT_GROUND then
|
||||
return set_mario_action(m, ACT_AXE_SPIN_AIR, 0)
|
||||
end
|
||||
|
||||
local gfx = m.marioObj.header.gfx
|
||||
local floorAngle = atan2s(m.floor.normal.z, m.floor.normal.x)
|
||||
local floorSlope = radians_to_sm64(math.acos(m.floor.normal.y))
|
||||
local speedTilt = math.clamp(m.forwardVel * 0x80, -0x500, 0x500)
|
||||
gfx.angle.x = floorSlope * coss(floorAngle - m.faceAngle.y) + speedTilt
|
||||
gfx.angle.z = floorSlope * -sins(floorAngle - m.faceAngle.y)
|
||||
|
||||
m.actionTimer = m.actionTimer + 1
|
||||
end
|
||||
|
||||
local function act_axe_spin_air(m)
|
||||
update_air_with_turn(m)
|
||||
m.vel.y = m.vel.y + 2
|
||||
|
||||
play_custom_anim(m, 'wapeach_axespin', math.clamp(m.forwardVel * 0x500, 0, 0x1F000))
|
||||
if is_anim_past_frame(m, 1) ~= 0 then
|
||||
play_sound(SOUND_ACTION_SPIN, m.marioObj.header.gfx.cameraToObject)
|
||||
end
|
||||
|
||||
if m.intendedMag > 1 then
|
||||
m.faceAngle.y = approach_s16_symmetric(m.faceAngle.y, m.intendedYaw, 0x200)
|
||||
end
|
||||
|
||||
m.forwardVel = math.clamp(m.forwardVel - 0.7, 0, 850)
|
||||
mario_set_forward_vel(m, m.forwardVel)
|
||||
|
||||
local step = perform_air_step(m, 0)
|
||||
if m.forwardVel < 20 and m.actionTimer >= 10 then
|
||||
set_mario_action(m, ACT_THROWN_FORWARD, 0)
|
||||
return
|
||||
end
|
||||
if m.forwardVel >= 100 and m.actionState == 0 then
|
||||
play_character_sound(m, CHAR_SOUND_TWIRL_BOUNCE)
|
||||
m.actionState = 1
|
||||
end
|
||||
if step == AIR_STEP_LANDED then
|
||||
return set_mario_action(m, ACT_AXE_SPIN, 0)
|
||||
end
|
||||
if step == AIR_STEP_HIT_WALL then
|
||||
mario_bonk_reflection(m, 1)
|
||||
return set_mario_action(m, ACT_THROWN_BACKWARD, 0)
|
||||
end
|
||||
|
||||
m.actionTimer = m.actionTimer + 1
|
||||
end
|
||||
|
||||
E_MODEL_DIZZYCIRCLE = smlua_model_util_get_id("dizzy_circle_geo")
|
||||
|
||||
---@param o Object
|
||||
local function bhv_dizzycircle_init(o)
|
||||
o.oFlags = OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE -- Allows you to change the position and angle
|
||||
end
|
||||
|
||||
---@param o Object
|
||||
local function bhv_dizzycircle_loop(o)
|
||||
smlua_anim_util_set_animation(o, 'dizzycircle_idle')
|
||||
local m = nearest_mario_state_to_object(o)
|
||||
|
||||
o.oPosX = m.marioBodyState.headPos.x
|
||||
o.oPosY = m.marioBodyState.headPos.y + 50
|
||||
|
||||
o.oPosZ = m.marioBodyState.headPos.z
|
||||
|
||||
|
||||
--pM = gMarioStates[network_local_index_from_global(o.globalPlayerIndex)]
|
||||
|
||||
if o.oTimer > 42 then -- Deletes itself once the action changes
|
||||
obj_mark_for_deletion(o)
|
||||
end
|
||||
end
|
||||
|
||||
local id_bhvDizzyCircle = hook_behavior(nil, OBJ_LIST_GENACTOR, true, bhv_dizzycircle_init, bhv_dizzycircle_loop, "bhvWapeachDizzyCircle")
|
||||
|
||||
local function act_axe_spin_dizzy(m)
|
||||
if m.actionTimer == 1 then
|
||||
play_character_sound(m, CHAR_SOUND_WHOA)
|
||||
-- Spawn the spin effect
|
||||
spawn_non_sync_object(id_bhvDizzyCircle, E_MODEL_DIZZYCIRCLE, m.marioBodyState.headPos.x,
|
||||
m.marioBodyState.headPos.y, m.marioBodyState.headPos.z,
|
||||
function(o)
|
||||
o.parentObj = m.marioObj
|
||||
o.globalPlayerIndex = m.marioObj.globalPlayerIndex
|
||||
end)
|
||||
end
|
||||
if m.actionTimer >= 42 then
|
||||
m.marioBodyState.eyeState = MARIO_EYES_DEAD
|
||||
set_character_animation(m, CHAR_ANIM_LAND_ON_STOMACH)
|
||||
smlua_anim_util_set_animation(m.marioObj, 'wapeach_flop')
|
||||
if m.actionTimer == 52 then
|
||||
play_sound(SOUND_ACTION_PAT_BACK, m.marioObj.header.gfx.cameraToObject)
|
||||
play_character_sound(m, CHAR_SOUND_OOOF2)
|
||||
end
|
||||
if m.actionTimer > 52 and m.actionTimer < 111 then
|
||||
apply_slope_accel(m)
|
||||
m.forwardVel = m.forwardVel * 0.95
|
||||
if m.forwardVel <= 0 then
|
||||
m.forwardVel = 0
|
||||
else
|
||||
set_mario_particle_flags(m, PARTICLE_DUST, 0)
|
||||
play_sound(SOUND_AIR_ROUGH_SLIDE, m.marioObj.header.gfx.cameraToObject)
|
||||
end
|
||||
elseif m.actionTimer >= 111 then
|
||||
m.forwardVel = 0
|
||||
if m.controller.buttonPressed & B_BUTTON ~= 0 or m.controller.buttonPressed & A_BUTTON ~= 0 then
|
||||
set_mario_action(m, ACT_FORWARD_ROLLOUT, 0)
|
||||
end
|
||||
end
|
||||
else
|
||||
apply_slope_accel(m)
|
||||
m.forwardVel = math.clamp(m.forwardVel, 0, 21)
|
||||
if is_anim_past_frame(m, 1) ~= 0 then
|
||||
play_sound(SOUND_ACTION_SPIN, m.marioObj.header.gfx.cameraToObject)
|
||||
end
|
||||
set_character_animation(m, CHAR_ANIM_BREAKDANCE)
|
||||
smlua_anim_util_set_animation(m.marioObj, 'wapeach_dizzy')
|
||||
end
|
||||
|
||||
mario_set_forward_vel(m, m.forwardVel)
|
||||
local step = perform_ground_step(m)
|
||||
if step == GROUND_STEP_LEFT_GROUND then
|
||||
set_mario_action(m, ACT_THROWN_FORWARD, 0)
|
||||
end
|
||||
|
||||
local gfx = m.marioObj.header.gfx
|
||||
local floorAngle = atan2s(m.floor.normal.z, m.floor.normal.x)
|
||||
local floorSlope = radians_to_sm64(math.acos(m.floor.normal.y))
|
||||
gfx.angle.x = floorSlope * coss(floorAngle - m.faceAngle.y)
|
||||
gfx.angle.z = floorSlope * -sins(floorAngle - m.faceAngle.y)
|
||||
|
||||
m.actionTimer = m.actionTimer + 1
|
||||
end
|
||||
|
||||
local axeOverrides = {
|
||||
[ACT_PUNCHING] = ACT_AXE_CHOP,
|
||||
[ACT_MOVE_PUNCHING] = ACT_AXE_CHOP,
|
||||
[ACT_SLIDE_KICK] = ACT_AXE_SPIN,
|
||||
}
|
||||
|
||||
---@param m MarioState
|
||||
---@param action integer
|
||||
function wapeach_before_action(m, action, actionArg)
|
||||
if axeOverrides[action] then
|
||||
if (action == ACT_PUNCHING or action == ACT_MOVE_PUNCHING) and actionArg ~= 9 then return end
|
||||
return axeOverrides[action]
|
||||
end
|
||||
end
|
||||
|
||||
hook_mario_action(ACT_AXE_CHOP, act_axe_chop)
|
||||
hook_mario_action(ACT_AXE_SPIN, act_axe_spin)
|
||||
hook_mario_action(ACT_AXE_SPIN_AIR, act_axe_spin_air)
|
||||
hook_mario_action(ACT_AXE_SPIN_DIZZY, act_axe_spin_dizzy)
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
-------------------
|
||||
-- Yoshi Moveset --
|
||||
-------------------
|
||||
|
||||
if not charSelect then return end
|
||||
|
||||
-- Flutterable actions, these don't match the DS flutterable actions
|
||||
local flutterActs = {
|
||||
[ACT_JUMP] = true,
|
||||
[ACT_DOUBLE_JUMP] = true,
|
||||
[ACT_TRIPLE_JUMP] = true,
|
||||
[ACT_LONG_JUMP] = true,
|
||||
[ACT_FREEFALL] = true
|
||||
}
|
||||
|
||||
_G.ACT_FLUTTER = allocate_mario_action(ACT_FLAG_AIR | ACT_FLAG_ALLOW_VERTICAL_WIND_ACTION | ACT_GROUP_AIRBORNE)
|
||||
YOSHI_ANIM_FLUTTER = 'yoshi_flutter_jump'
|
||||
|
||||
---@param m MarioState
|
||||
function act_flutter(m)
|
||||
-- End flutter after 1 second
|
||||
if m.actionTimer >= 30 or (m.input & INPUT_A_DOWN) == 0 then
|
||||
if m.actionTimer < 30 then
|
||||
play_character_sound(m, CHAR_SOUND_MAX) -- Stop sample after letting go of A
|
||||
end
|
||||
return set_mario_action(m, ACT_FREEFALL, 0)
|
||||
end
|
||||
|
||||
local ended = common_air_action_step(m, ACT_JUMP_LAND, CHAR_ANIM_RUNNING_UNUSED, 0) ~= 0 -- Checks if the action ended earlier due to forced actions like bonking or landing
|
||||
|
||||
if ended then
|
||||
play_character_sound(m, CHAR_SOUND_MAX) -- Stop sample after landing
|
||||
elseif m.actionTimer == 0 then
|
||||
play_character_sound(m, YOSHI_SOUND_FLUTTER) -- Play audio sample
|
||||
end
|
||||
|
||||
smlua_anim_util_set_animation(m.marioObj, YOSHI_ANIM_FLUTTER) -- Sets the animation
|
||||
|
||||
m.marioBodyState.eyeState = MARIO_EYES_CLOSED -- Eye State
|
||||
m.vel.y = approach_f32(m.vel.y, m.actionTimer / 1.25, 8, 8) -- Height increases faster as the 1 second passes
|
||||
m.marioObj.header.gfx.animInfo.animAccel = 0x10000 * 2 -- Anim Speed
|
||||
|
||||
m.actionTimer = m.actionTimer + 1
|
||||
return false
|
||||
end
|
||||
|
||||
---@param m MarioState
|
||||
function yoshi_update(m)
|
||||
if m.prevAction & ACT_FLAG_AIR == 0 and m.action & ACT_FLAG_AIR ~= 0 and flutterActs[m.action] and m.controller.buttonDown & A_BUTTON ~= 0 and m.vel.y < 0 then
|
||||
set_mario_action(m, ACT_FLUTTER, 0)
|
||||
end
|
||||
end
|
||||
|
||||
hook_mario_action(ACT_FLUTTER, act_flutter)
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue