-- name: Characters Physics \\#A0A0A0\\(Explosive Flavour) -- description: Adds custom physics/stats to each characters of the vannila cast, Including diferrent maxium speed, acceleration, decelartion, jump height, swim speed and weight stats! \nMade by ExploxionMach -- ========================================================= -- CORE FUNCTIONS AND LOCALS -- ========================================================= local characterPhysics = { [CT_MARIO] = { maxSpeed = 31, accel = 0, decel = 0, jumpHeight = 0, swimSpeed = 1, weight = 1 }, [CT_LUIGI] = { maxSpeed = 27, accel = 0, decel = 3.3, jumpHeight = 10, swimSpeed = 1.25, weight = 0.2 }, [CT_TOAD] = { maxSpeed = 41, accel = 1.25, decel = 2, jumpHeight = -7.5, swimSpeed = 1.5, weight = 0.4 }, [CT_WARIO] = { maxSpeed = 31, accel = -0.15, 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_HOLD_JUMP] = true, [ACT_HOLD_WALKING] = 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_RIDING_SHELL_JUMP] = 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 id = m.playerIndex if currentAction[id] == nil then currentAction[id] = m.action lastAction[id] = m.action return end if m.action ~= currentAction[id] then lastAction[id] = currentAction[id] currentAction[id] = 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.action == ACT_HOLD_WALKING then maxSpeed = maxSpeed * 0.5 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 decelSpeed = {} local function physics_decel(m) local _, phys, id = get_char_data(m) if m.action == ACT_BRAKING or m.action == ACT_TURNING_AROUND then m.forwardVel = m.forwardVel + phys.decel if decelSpeed[id] == nil then decelSpeed[id] = m.forwardVel end if m.forwardVel < decelSpeed[id] then decelSpeed[id] = m.forwardVel else m.forwardVel = decelSpeed[id] end else decelSpeed[id] = m.forwardVel end if m.action == ACT_DECELERATING or m.action == ACT_HOLD_DECELERATING then m.forwardVel = m.forwardVel + (phys.decel * 0.1) 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) elseif m.forwardVel < -5 then 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.forwardVel > (phys.maxSpeed - 3) and customActionTimer[id] < 1 then if (m.action == ACT_MOVE_PUNCHING or m.action == ACT_PUNCHING) or m.action == ACT_JUMP_KICK then set_mario_action(m, ACT_DIVE, 0) if m.action & ACT_FLAG_AIR == 0 then m.vel.y = 16 end 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 or m.action == ACT_WATER_PUNCH or m.action == ACT_WATER_SHELL_SWIMMING) 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 not knockBackActs[last] then local kbScale = 1 + ((1 - phys.weight) * 0.3) if m.action & ACT_FLAG_SWIMMING == 0 then if customActionTimer[id] < 10 then m.forwardVel = m.forwardVel * kbScale end else if customActionTimer[id] < 1 then m.forwardVel = m.forwardVel * kbScale end end 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 characters_info() djui_chat_message_create("\\#FF0000\\Mario: \\#E7E7E7\\| Max Spd: Medium | Accel: Medium | Decel: Medium") djui_chat_message_create("\\#E7E7E7\\Jump: Medium | Swim Spd: Medium | Weight: Medium") djui_chat_message_create("\\#00FF00\\Luigi: \\#E7E7E7\\| Max Spd: Low | Accel: High | Decel: Very Low") djui_chat_message_create("\\#E7E7E7\\Jump: Very High | Swim Spd: High | Weight: Very Low") djui_chat_message_create("\\#0000FF\\Toad: \\#E7E7E7\\| Max Spd: Very High | Accel: Very High | Decel: Low") djui_chat_message_create("\\#E7E7E7\\Jump: Low | Swim Spd: Very High | Weight: Low") djui_chat_message_create("\\#FFDA00\\Wario: \\#E7E7E7\\| Max Spd: Medium | Accel: Very Low | Decel: Very High") djui_chat_message_create("\\#E7E7E7\\Jump: Low | Swim Spd: High | Weight: Very High") djui_chat_message_create("\\#AA00FF\\Waluigi: \\#E7E7E7\\| Max Spd: High | Accel: High | Decel: High") djui_chat_message_create("\\#E7E7E7\\Jump: High | Swim Spd: Low | Weight: Low") end local function stats_info() djui_chat_message_create("\\#00BEFF\\Maximum Speed: \\#E7E7E7\\Determines top speed.") djui_chat_message_create("\\#00BEFF\\Acceleration: \\#E7E7E7\\Determines speed gain.") djui_chat_message_create("\\#00BEFF\\Deceleration: \\#E7E7E7\\Determines braking and turnaround speed.") djui_chat_message_create("\\#00BEFF\\Jump Height: \\#E7E7E7\\Determines jump height.") djui_chat_message_create("\\#00BEFF\\Swim Speed: \\#E7E7E7\\Determines swimming speed.") djui_chat_message_create("\\#00BEFF\\Weight: \\#E7E7E7\\Affects falling speed and knockback resistance.") end hook_mod_menu_checkbox("Unique Characters Physics", playerSettings.physics, toggle_physics) hook_mod_menu_button("Show Characters Physics/Stats", characters_info) hook_mod_menu_button("Show Physics/Stats Info", stats_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)