-- name: Characters Physics (Explosive Flavour) -- description: Adds custom physics to each characters of the vannila cast, Including diferrent maxium speed, acceleration, decelartion, jump height, swim speed and weight stats! -ExploxionMach -- ========================================================= -- CORE FUNCTIONS AND LOCALS -- ========================================================= local characterPhysics = { [CT_MARIO] = { maxSpeed = 31, accel = 0, decel = 0, jumpHeight = 0, swimSpeed = 1, weight = 1 }, [CT_LUIGI] = { maxSpeed = 28, accel = 0, decel = 3.25, jumpHeight = 10, swimSpeed = 1.25, weight = 0.2 }, [CT_TOAD] = { maxSpeed = 41, accel = 1.5, decel = 2, jumpHeight = -7.5, swimSpeed = 1.5, weight = 0.4 }, [CT_WARIO] = { maxSpeed = 31, accel = -0.16, decel = -2, jumpHeight = -5, swimSpeed = 1.25, weight = 1.8 }, [CT_WALUIGI] = { maxSpeed = 34, accel = 0.5, decel = -1, jumpHeight = 5, swimSpeed = 0.75, weight = 0.4 } } local accelActs = { [ACT_WALKING] = true, [ACT_FINISH_TURNING_AROUND] = true, [ACT_AIR_THROW] = true, [ACT_JUMP] = true, [ACT_JUMP_KICK] = true, [ACT_DOUBLE_JUMP] = true, [ACT_TRIPLE_JUMP] = true, [ACT_BACKFLIP] = true, [ACT_SIDE_FLIP] = true, [ACT_WALL_KICK_AIR] = true, [ACT_FREEFALL] = true } local jumpActs = { [ACT_JUMP] = true, [ACT_WATER_JUMP] = true, [ACT_HOLD_JUMP] = true, [ACT_STEEP_JUMP] = true, [ACT_BURNING_JUMP] = true, [ACT_TOP_OF_POLE_JUMP] = true, [ACT_DOUBLE_JUMP] = true, [ACT_TRIPLE_JUMP] = true, [ACT_SPECIAL_TRIPLE_JUMP] = true, [ACT_LONG_JUMP] = true, [ACT_BACKFLIP] = true, [ACT_SIDE_FLIP] = true, [ACT_WALL_KICK_AIR] = true } local knockBackActs = { [ACT_BACKWARD_WATER_KB] = true, [ACT_FORWARD_WATER_KB] = true, [ACT_SOFT_FORWARD_GROUND_KB] = true, [ACT_SOFT_BACKWARD_GROUND_KB] = true, [ACT_GROUND_BONK] = true, [ACT_BACKWARD_AIR_KB] = true, [ACT_HARD_BACKWARD_GROUND_KB] = true, [ACT_BACKWARD_GROUND_KB] = true, [ACT_FORWARD_AIR_KB] = true, [ACT_FORWARD_GROUND_KB] = true, [ACT_THROWN_FORWARD] = true, [ACT_GETTING_BLOWN] = true, [ACT_DEATH_EXIT] = true } local playerSettings = { physics = true } local function toggle_physics(index, value) playerSettings.physics = value end local function get_character_type(m) if m.character and m.character.type ~= nil then return m.character.type end if _G.charSelect and type(_G.charSelect.get_current_character) == "function" and m.playerIndex ~= nil then return _G.charSelect.get_current_character(m.playerIndex) end return nil end local function get_char_data(m) if not m or m.playerIndex == nil then return end local char = get_character_type(m) if not char then return end local phys = characterPhysics[char] if not phys then return end return char, phys, m.playerIndex end local function get_signed_slope(m) if not m.floor then return 0 end local normal = m.floor.normal local moveYaw = m.faceAngle.y local forwardX = sins(moveYaw) local forwardZ = coss(moveYaw) local dot = (forwardX * normal.x) + (forwardZ * normal.z) return dot end function approach_s16(current, target, step) local diff = (target - current + 0x8000) % 0x10000 - 0x8000 if diff > step then return current + step elseif diff < -step then return current - step else return target end end local customActionTimer = {} local function update_custom_action_timer(m) local id = m.playerIndex if customActionTimer[id] == nil then customActionTimer[id] = 0 end customActionTimer[id] = customActionTimer[id] + 1 end local lastAction = {} local currentAction = {} function update_action_history(m) local i = m.playerIndex if currentAction[i] == nil then currentAction[i] = m.action lastAction[i] = m.action return end if m.action ~= currentAction[i] then lastAction[i] = currentAction[i] currentAction[i] = m.action end end -- ========================================================= -- PHYSICS FUNCTIONS -- ========================================================= local function physics_accel(m) local _, phys = get_char_data(m) local angleDiff = (m.intendedYaw - m.faceAngle.y + 0x8000) % 0x10000 - 0x8000 local absDiff = math.abs(angleDiff) local angleThreshold = 0x2000 if accelActs[m.action] and m.input & INPUT_NONZERO_ANALOG ~= 0 and absDiff < angleThreshold and m.forwardVel > 0 or m.action == ACT_BURNING_GROUND then local maxSpeed = phys.maxSpeed local accel = phys.accel local slope = get_signed_slope(m) local slopeAbs = math.abs(slope) if m.forwardVel > 31 and maxSpeed > 31 then accel = accel + 1 end if m.action & ACT_FLAG_AIR ~= 0 then if phys.accel > 0 then accel = accel * 0.5 else accel = accel * 1.25 end else if slope < 0 then maxSpeed = maxSpeed - (slopeAbs * 10) accel = accel - (slopeAbs * 0.3) else maxSpeed = maxSpeed + (slopeAbs * 10) accel = accel + (slopeAbs * 0.3) end end if m.forwardVel < maxSpeed then local diff = maxSpeed - m.forwardVel local proportional = diff * accel local step = accel + (proportional * 0.1) m.forwardVel = m.forwardVel + step end if m.forwardVel > maxSpeed and m.forwardVel < (maxSpeed + 10) then local excess = m.forwardVel - maxSpeed m.forwardVel = m.forwardVel - (excess * 0.4) end end end local function physics_decel(m) local _, phys = get_char_data(m) if m.action == ACT_BRAKING or m.action == ACT_TURNING_AROUND then m.forwardVel = m.forwardVel + phys.decel if m.forwardVel < 0 then m.forwardVel = 0 end end if m.action == ACT_FINISH_TURNING_AROUND and phys.decel < 0 then set_mario_action(m, ACT_WALKING, 0) m.forwardVel = m.forwardVel - phys.decel * 6 end end local function physics_jump_height(m) local _, phys, id = get_char_data(m) if jumpActs[m.action] then if m.action == ACT_WALL_KICK_AIR then m.forwardVel = m.forwardVel - phys.jumpHeight * 1.1 end m.vel.y = m.vel.y + phys.jumpHeight end end local function physics_mobility_moves(m) local _, phys, id = get_char_data(m) if m.action == ACT_LONG_JUMP then if m.forwardVel > 0 then m.forwardVel = m.forwardVel + (phys.maxSpeed - 31) else m.forwardVel = m.forwardVel - (phys.maxSpeed - 31) end end if m.action == ACT_DIVE then m.forwardVel = m.forwardVel + (phys.maxSpeed - 31) end end local function physics_attack_moves(m) local _, phys, id = get_char_data(m) local last = lastAction[id] if (m.action == ACT_MOVE_PUNCHING or m.action == ACT_PUNCHING) or (m.action == ACT_JUMP_KICK and m.controller.buttonDown & A_BUTTON == 0) then if m.forwardVel > (phys.maxSpeed - 2) and customActionTimer[id] == 1 then set_mario_action(m, ACT_DIVE, 0) m.vel.y = 16 end end end local function physics_swim(m) local _, phys = get_char_data(m) local hScale = 1.0 local vScale = 1.0 if m.action & ACT_FLAG_SWIMMING ~= 0 and (m.action == ACT_BREASTSTROKE or m.action == ACT_SWIMMING_END) then hScale = hScale * phys.swimSpeed vScale = vScale * phys.swimSpeed end m.vel.x = m.vel.x * hScale m.vel.y = m.vel.y * vScale m.vel.z = m.vel.z * hScale end local function physics_weight(m) local _, phys, id = get_char_data(m) local last = lastAction[id] if m.vel.y < 0 and jumpActs[m.action] and m.action ~= ACT_LONG_JUMP or knockBackActs[m.action] or m.action == ACT_FREEFALL then local gravity = (phys.weight - 1) * 2 m.vel.y = m.vel.y - gravity m.peakHeight = m.peakHeight + gravity end if m.action == ACT_WATER_PLUNGE then local gravity = (phys.weight - 1) m.vel.y = m.vel.y - gravity end if knockBackActs[m.action] and customActionTimer[id] < 10 and not knockBackActs[last] then local kbScale = 1 + ((1 - phys.weight) * 0.4) m.forwardVel = m.forwardVel * kbScale end end -- ========================================================= -- APPLY FUNCTIONS -- ========================================================= local function apply_physics_before_phys(m) if not playerSettings.physics then return end physics_accel(m) physics_decel(m) physics_attack_moves(m) physics_swim(m) physics_weight(m) end local function apply_physics_action(m) if not playerSettings.physics then return end physics_jump_height(m) physics_mobility_moves(m) end -- ========================================================= -- MOD MENU -- ========================================================= local function mario_info() djui_chat_message_create("Max Speed: Medium | Accel: Medium | Decel: Medium") djui_chat_message_create("Jump Height: Medium | Swim Speed: Medium") djui_chat_message_create("Weight: Medium") end local function luigi_info() djui_chat_message_create("Max Speed: Low | Accel: High | Decel: Very Low") djui_chat_message_create("Jump Height: Very High | Swim Speed: High") djui_chat_message_create("Weight: Very Low") end local function toad_info() djui_chat_message_create("Max Speed: Very High | Accel: Very High | Decel: Low") djui_chat_message_create("Jump Height: Low | Swim Speed: Very High") djui_chat_message_create("Weight: Low") end local function wario_info() djui_chat_message_create("Max Speed: Medium | Accel: Very Low | Decel: Very High") djui_chat_message_create("Jump Height: Low | Swim Speed: High") djui_chat_message_create("Weight: Very High") end local function waluigi_info() djui_chat_message_create("Max Speed: High | Accel: High | Decel: High") djui_chat_message_create("Jump Height: High | Swim Speed: Low") djui_chat_message_create("Weight: Low") end hook_mod_menu_checkbox("Unique Characters Physics", playerSettings.physics, toggle_physics) hook_mod_menu_button("\\#FF0000\\Mario Info", mario_info) hook_mod_menu_button("\\#00FF00\\Luigi Info", luigi_info) hook_mod_menu_button("\\#0000FF\\Toad Info", toad_info) hook_mod_menu_button("\\#FFDA00\\Wario Info", wario_info) hook_mod_menu_button("\\#AA00FF\\Waluigi Info", waluigi_info) -- ========================================================= -- HOOKS -- ========================================================= hook_event(HOOK_MARIO_UPDATE, update_custom_action_timer) hook_event(HOOK_BEFORE_PHYS_STEP, apply_physics_before_phys) hook_event(HOOK_ON_SET_MARIO_ACTION, apply_physics_action) hook_event(HOOK_MARIO_UPDATE, update_action_history) hook_event(HOOK_ON_SET_MARIO_ACTION, function(m) customActionTimer[m.playerIndex] = 0 end)