mirror of
				https://github.com/coop-deluxe/sm64coopdx.git
				synced 2025-10-30 08:01:01 +00:00 
			
		
		
		
	The Same Bug from Last Time is there but effects the first box instead, so I went to check and fixed what went wrong with the mod
		
			
				
	
	
		
			383 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			383 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
-- name: Cheats
 | 
						||
-- incompatible: cheats
 | 
						||
-- description: Cheats\nA mod that adds a bunch of cheats to the mod menu, accessible through the pause menu.
 | 
						||
 | 
						||
-- localize functions to improve performance
 | 
						||
local math_floor,smlua_text_utils_get_language,table_insert,approach_s32,set_mario_action,get_network_area_timer = math.floor,smlua_text_utils_get_language,table.insert,approach_s32,set_mario_action,get_network_area_timer
 | 
						||
 | 
						||
--- @class Cheat
 | 
						||
--- @field public codename string
 | 
						||
--- @field public names table
 | 
						||
--- @field public hook LuaHookedEventType
 | 
						||
--- @field public func function
 | 
						||
--- @field public allowHazardSurfaces boolean
 | 
						||
 | 
						||
local CHEATS_VERSION = "v1.0"
 | 
						||
 | 
						||
--- @type Cheat[]
 | 
						||
local sCheats = {}
 | 
						||
 | 
						||
--- @param m MarioState
 | 
						||
--- Checks if `m` is active
 | 
						||
local function active_player(m)
 | 
						||
    local np = gNetworkPlayers[m.playerIndex]
 | 
						||
    if m.playerIndex == 0 then
 | 
						||
        return true
 | 
						||
    end
 | 
						||
    if not np.connected then
 | 
						||
        return false
 | 
						||
    end
 | 
						||
    if np.currCourseNum ~= gNetworkPlayers[0].currCourseNum then
 | 
						||
        return false
 | 
						||
    end
 | 
						||
    if np.currActNum ~= gNetworkPlayers[0].currActNum then
 | 
						||
        return false
 | 
						||
    end
 | 
						||
    if np.currLevelNum ~= gNetworkPlayers[0].currLevelNum then
 | 
						||
        return false
 | 
						||
    end
 | 
						||
    if np.currAreaIndex ~= gNetworkPlayers[0].currAreaIndex then
 | 
						||
        return false
 | 
						||
    end
 | 
						||
    return true
 | 
						||
end
 | 
						||
 | 
						||
--- @param num integer
 | 
						||
--- Limits an integer in the s16 range
 | 
						||
local function s16(num)
 | 
						||
    num = math_floor(num) & 0xFFFF
 | 
						||
    if num >= 32768 then return num - 65536 end
 | 
						||
    return num
 | 
						||
end
 | 
						||
 | 
						||
local function lang_string(strings)
 | 
						||
    local table = strings[smlua_text_utils_get_language()]
 | 
						||
    if table == nil then return strings["English"] end
 | 
						||
    return table
 | 
						||
end
 | 
						||
 | 
						||
--- @param codename string
 | 
						||
--- @param names table<string, string>
 | 
						||
--- @param hook LuaHookedEventType
 | 
						||
--- @param func function
 | 
						||
--- @param allowHazardSurfaces boolean
 | 
						||
--- Registers a cheat
 | 
						||
---
 | 
						||
--- Supported hooks:
 | 
						||
--- - `HOOK_MARIO_UPDATE`
 | 
						||
--- - `HOOK_BEFORE_MARIO_UPDATE`
 | 
						||
--- - `HOOK_BEFORE_PHYS_STEP`
 | 
						||
local function register_cheat(codename, names, hook, func, allowHazardSurfaces)
 | 
						||
    table_insert(sCheats, {
 | 
						||
        codename = codename,
 | 
						||
        names = names,
 | 
						||
        hook = hook,
 | 
						||
        func = func,
 | 
						||
        allowHazardSurfaces = allowHazardSurfaces
 | 
						||
    })
 | 
						||
 | 
						||
    for i = 0, MAX_PLAYERS - 1 do
 | 
						||
        gPlayerSyncTable[i][codename] = false
 | 
						||
    end
 | 
						||
end
 | 
						||
 | 
						||
--- @param m MarioState
 | 
						||
local function moon_jump_update(m)
 | 
						||
    if m.controller.buttonDown & L_TRIG ~= 0 then
 | 
						||
        m.faceAngle.y = m.intendedYaw - approach_s32(s16(m.intendedYaw - m.faceAngle.y), 0, 0x800, 0x800)
 | 
						||
        m.vel.y = 40
 | 
						||
 | 
						||
        if m.action == ACT_FORWARD_GROUND_KB or
 | 
						||
           m.action == ACT_BACKWARD_GROUND_KB or
 | 
						||
           m.action == ACT_SOFT_FORWARD_GROUND_KB or
 | 
						||
           m.action == ACT_HARD_BACKWARD_GROUND_KB or
 | 
						||
           m.action == ACT_FORWARD_AIR_KB or
 | 
						||
           m.action == ACT_BACKWARD_AIR_KB or
 | 
						||
           m.action == ACT_HARD_FORWARD_AIR_KB or
 | 
						||
           m.action == ACT_HARD_BACKWARD_AIR_KB or
 | 
						||
           m.action == ACT_AIR_HIT_WALL then
 | 
						||
            set_mario_action(m, ACT_FREEFALL, 0)
 | 
						||
        end
 | 
						||
    end
 | 
						||
end
 | 
						||
 | 
						||
--- @param m MarioState
 | 
						||
local function god_mode_update(m)
 | 
						||
    m.health = 0x880
 | 
						||
    m.healCounter = 0
 | 
						||
    m.hurtCounter = 0
 | 
						||
    m.peakHeight = m.pos.y
 | 
						||
end
 | 
						||
 | 
						||
--- @param m MarioState
 | 
						||
local function infinite_lives_update(m)
 | 
						||
    m.numLives = 100
 | 
						||
end
 | 
						||
 | 
						||
--- @param m MarioState
 | 
						||
local function super_speed_update(m)
 | 
						||
    if m.action ~= ACT_BUBBLED and m.action ~= ACT_WATER_JUMP and m.action ~= ACT_HOLD_WATER_JUMP then
 | 
						||
        m.vel.x = m.vel.x * 4
 | 
						||
        m.vel.z = m.vel.z * 4
 | 
						||
    end
 | 
						||
end
 | 
						||
 | 
						||
--- @param m MarioState
 | 
						||
local function responsive_controls_update(m)
 | 
						||
    if m.action == ACT_WALKING or
 | 
						||
       m.action == ACT_HOLD_WALKING or
 | 
						||
       m.action == ACT_HOLD_HEAVY_WALKING or
 | 
						||
       m.action == ACT_FINISH_TURNING_AROUND or
 | 
						||
       m.action == ACT_CRAWLING then
 | 
						||
        m.faceAngle.y = m.intendedYaw
 | 
						||
    end
 | 
						||
end
 | 
						||
 | 
						||
--- @param m MarioState
 | 
						||
local function rapid_fire_update(m)
 | 
						||
    if (m.controller.buttonDown & A_BUTTON) ~= 0 and get_global_timer() % 2 == 0 then
 | 
						||
        m.controller.buttonPressed = m.controller.buttonPressed | A_BUTTON
 | 
						||
    end
 | 
						||
end
 | 
						||
 | 
						||
local function blj_anywhere_update(m)
 | 
						||
    if m.action == ACT_LONG_JUMP and
 | 
						||
       m.controller.buttonDown & Z_TRIG ~= 0 and
 | 
						||
       m.forwardVel < -15 then
 | 
						||
        m.vel.y = -30
 | 
						||
	end
 | 
						||
end
 | 
						||
 | 
						||
local function always_triple_jump_update(m, action)
 | 
						||
    if m.forwardVel < 20 and m.action == ACT_DOUBLE_JUMP_LAND and action == ACT_JUMP then
 | 
						||
        return ACT_TRIPLE_JUMP
 | 
						||
	end
 | 
						||
end
 | 
						||
 | 
						||
register_cheat(
 | 
						||
    "moonJump",
 | 
						||
    {
 | 
						||
        ["Czech"] = "Nekonečný Skok",
 | 
						||
        ["Dutch"] = "Maan Sprong",
 | 
						||
        ["English"] = "Moon Jump",
 | 
						||
        ["French"] = "Saut Antigravité",
 | 
						||
        ["German"] = "Mond-Sprung",
 | 
						||
        ["Italian"] = "Salto della Luna",
 | 
						||
        ["Polish"] = "Skok Ksiezycowy",
 | 
						||
        ["Portuguese"] = "Pulo da Lua",
 | 
						||
        ["Russian"] = "Супер прыжок",
 | 
						||
        ["Spanish"] = "Salto Lunar"
 | 
						||
    },
 | 
						||
    HOOK_MARIO_UPDATE,
 | 
						||
    moon_jump_update,
 | 
						||
    true
 | 
						||
)
 | 
						||
 | 
						||
register_cheat(
 | 
						||
    "godMode",
 | 
						||
    {
 | 
						||
        ["Czech"] = "Nenech Se Zranit",
 | 
						||
        ["Dutch"] = "God Modus",
 | 
						||
        ["English"] = "God Mode",
 | 
						||
        ["French"] = "Mode Invincible",
 | 
						||
        ["German"] = "Gott Modus",
 | 
						||
        ["Italian"] = "Modalità Dio",
 | 
						||
        ["Polish"] = "Tryb Boga",
 | 
						||
        ["Portuguese"] = "Modo Deus",
 | 
						||
        ["Russian"] = "Режим бога",
 | 
						||
        ["Spanish"] = "Modo Dios",
 | 
						||
    },
 | 
						||
    HOOK_MARIO_UPDATE,
 | 
						||
    god_mode_update,
 | 
						||
    false
 | 
						||
)
 | 
						||
 | 
						||
register_cheat(
 | 
						||
    "infiniteLives",
 | 
						||
    {
 | 
						||
        ["Czech"] = "Nekonečné Životy",
 | 
						||
        ["Dutch"] = "Oneindige Levens",
 | 
						||
        ["English"] = "Infinite Lives",
 | 
						||
        ["French"] = "Vies Infinies",
 | 
						||
        ["German"] = "Unbegrenzte Leben",
 | 
						||
        ["Italian"] = "Vite Infinite",
 | 
						||
        ["Polish"] = "Nieskonczone Zycia",
 | 
						||
        ["Portuguese"] = "Vidas Infinitas",
 | 
						||
        ["Russian"] = "Бесконечные жизни",
 | 
						||
        ["Spanish"] = "Vidas Infinitas",
 | 
						||
    },
 | 
						||
    HOOK_MARIO_UPDATE,
 | 
						||
    infinite_lives_update,
 | 
						||
    true
 | 
						||
)
 | 
						||
 | 
						||
register_cheat(
 | 
						||
    "superSpeed",
 | 
						||
    {
 | 
						||
        ["Czech"] = "Super Rychlost",
 | 
						||
        ["Dutch"] = "Super Snelheid",
 | 
						||
        ["English"] = "Super Speed",
 | 
						||
        ["French"] = "Super Vitesse",
 | 
						||
        ["German"] = "Supergeschwindigkeit",
 | 
						||
        ["Italian"] = "Super Velocità",
 | 
						||
        ["Polish"] = "Super Szybkosc",
 | 
						||
        ["Portuguese"] = "Super Velocidade",
 | 
						||
        ["Russian"] = "Супер cкорость",
 | 
						||
        ["Spanish"] = "Super Velocidad",
 | 
						||
    },
 | 
						||
    HOOK_BEFORE_PHYS_STEP,
 | 
						||
    super_speed_update,
 | 
						||
    true
 | 
						||
)
 | 
						||
 | 
						||
register_cheat(
 | 
						||
    "responsiveControls",
 | 
						||
    {
 | 
						||
        ["Czech"] = "Citlivé Ovládání",
 | 
						||
        ["Dutch"] = "Snel Reagerende Controles",
 | 
						||
        ["English"] = "Responsive Controls",
 | 
						||
        ["French"] = "Contrôles Réactifs",
 | 
						||
        ["German"] = "Reaktionsschnelle Steuerung",
 | 
						||
        ["Italian"] = "Controlli Reattivi",
 | 
						||
        ["Polish"] = "Responsywne Sterowanie",
 | 
						||
        ["Portuguese"] = "Controle Responsivos",
 | 
						||
        ["Russian"] = "Отзывчивое управление",
 | 
						||
        ["Spanish"] = "Controles Responsivos",
 | 
						||
    },
 | 
						||
    HOOK_MARIO_UPDATE,
 | 
						||
    responsive_controls_update,
 | 
						||
    true
 | 
						||
)
 | 
						||
 | 
						||
register_cheat(
 | 
						||
    "rapidFire",
 | 
						||
    {
 | 
						||
        ["Czech"] = "Rychle Mačkat Tlačítko",
 | 
						||
        ["Dutch"] = "Snel Vuur",
 | 
						||
        ["English"] = "Rapid Fire",
 | 
						||
        ["French"] = "Tir Rapide",
 | 
						||
        ["German"] = "Schnellfeuer",
 | 
						||
        ["Italian"] = "Fuoco Rapido",
 | 
						||
        ["Polish"] = "Szybkostrzelnosc",
 | 
						||
        ["Portuguese"] = "Fogo Rápido",
 | 
						||
        ["Russian"] = "Быстрый огонь",
 | 
						||
        ["Spanish"] = "Pulsación Rápida",
 | 
						||
    },
 | 
						||
    HOOK_BEFORE_MARIO_UPDATE,
 | 
						||
    rapid_fire_update,
 | 
						||
    true
 | 
						||
)
 | 
						||
 | 
						||
register_cheat(
 | 
						||
    "bljAnywhere",
 | 
						||
    {
 | 
						||
        ["Czech"] = "BLJ Všude",
 | 
						||
        ["Dutch"] = "BLJ Overal",
 | 
						||
        ["English"] = "BLJ Anywhere",
 | 
						||
        ["French"] = "BLJ N'importe Où",
 | 
						||
        ["German"] = "Überall Rückwertsweitspringen",
 | 
						||
        ["Italian"] = "BLJ Ovunque",
 | 
						||
        ["Polish"] = "BLJ Gdziekolwiek",
 | 
						||
        ["Portuguese"] = "BLJ Em Qualquer Lugar",
 | 
						||
        ["Russian"] = "BLJ в любом месте",
 | 
						||
        ["Spanish"] = "BLJ Donde Sea",
 | 
						||
    },
 | 
						||
    HOOK_BEFORE_MARIO_UPDATE,
 | 
						||
    blj_anywhere_update,
 | 
						||
    true
 | 
						||
)
 | 
						||
 | 
						||
register_cheat(
 | 
						||
    "alwaysTripleJump",
 | 
						||
    {
 | 
						||
        ["Czech"] = "Vždy Trojitý Skok",
 | 
						||
        ["Dutch"] = "Altijd Drievoudige Sprong",
 | 
						||
        ["English"] = "Always Triple Jump",
 | 
						||
        ["French"] = "Triple Sauts Infinis",
 | 
						||
        ["German"] = "Immer Dreisprung",
 | 
						||
        ["Italian"] = "Sempre Salto Triplo",
 | 
						||
        ["Polish"] = "Potrojny Skok Zawsze",
 | 
						||
        ["Portuguese"] = "Sempre Fazer Triple Jump",
 | 
						||
        ["Russian"] = "Всегда тройной прыжок",
 | 
						||
        ["Spanish"] = "Siempre Hacer Salto Triple",
 | 
						||
    },
 | 
						||
    HOOK_BEFORE_SET_MARIO_ACTION,
 | 
						||
    always_triple_jump_update,
 | 
						||
    true
 | 
						||
)
 | 
						||
 | 
						||
--- @param hookType LuaHookedEventType
 | 
						||
local function generate_mario_hook_function(hookType)
 | 
						||
    --- @param m MarioState
 | 
						||
    return function(m)
 | 
						||
        if not active_player(m) then return end
 | 
						||
 | 
						||
        for _, cheat in ipairs(sCheats) do
 | 
						||
            if cheat.hook == hookType and gPlayerSyncTable[m.playerIndex][cheat.codename] then
 | 
						||
                cheat.func(m)
 | 
						||
            end
 | 
						||
        end
 | 
						||
    end
 | 
						||
end
 | 
						||
 | 
						||
local function before_set_mario_action(m, action)
 | 
						||
    if not active_player(m) then return end
 | 
						||
 | 
						||
    for _, cheat in ipairs(sCheats) do
 | 
						||
        if cheat.hook == HOOK_BEFORE_SET_MARIO_ACTION and gPlayerSyncTable[m.playerIndex][cheat.codename] then
 | 
						||
            return cheat.func(m, action)
 | 
						||
        end
 | 
						||
    end
 | 
						||
end
 | 
						||
 | 
						||
--- @param m MarioState
 | 
						||
local function allow_hazard_surface(m)
 | 
						||
    for _, cheat in ipairs(sCheats) do
 | 
						||
        if gPlayerSyncTable[m.playerIndex][cheat.codename] and not cheat.allowHazardSurfaces then return false end
 | 
						||
    end
 | 
						||
    return true
 | 
						||
end
 | 
						||
 | 
						||
local function on_language_changed()
 | 
						||
    for i, cheat in ipairs(sCheats) do
 | 
						||
        update_mod_menu_element_name(i - 1, lang_string(cheat.names))
 | 
						||
    end
 | 
						||
end
 | 
						||
 | 
						||
 | 
						||
--- @param index integer
 | 
						||
--- @param value boolean
 | 
						||
local function update_cheat(index, value)
 | 
						||
    for i, cheat in ipairs(sCheats) do
 | 
						||
        if i == index + 1 then
 | 
						||
            gPlayerSyncTable[0][cheat.codename] = value
 | 
						||
        end
 | 
						||
    end
 | 
						||
end
 | 
						||
 | 
						||
local sReadonlyMetatable = {
 | 
						||
    __index = function(table, key)
 | 
						||
        return rawget(table, key)
 | 
						||
    end,
 | 
						||
 | 
						||
    __newindex = function()
 | 
						||
        error("attempt to update a read-only table", 2)
 | 
						||
    end
 | 
						||
}
 | 
						||
 | 
						||
_G.cheatsApi = {
 | 
						||
    version = CHEATS_VERSION,
 | 
						||
    register_cheat = register_cheat
 | 
						||
}
 | 
						||
setmetatable(_G.cheatsApi, sReadonlyMetatable)
 | 
						||
 | 
						||
hook_event(HOOK_MARIO_UPDATE, generate_mario_hook_function(HOOK_MARIO_UPDATE))
 | 
						||
hook_event(HOOK_BEFORE_MARIO_UPDATE, generate_mario_hook_function(HOOK_BEFORE_MARIO_UPDATE))
 | 
						||
hook_event(HOOK_BEFORE_PHYS_STEP, generate_mario_hook_function(HOOK_BEFORE_PHYS_STEP))
 | 
						||
hook_event(HOOK_BEFORE_SET_MARIO_ACTION, before_set_mario_action)
 | 
						||
hook_event(HOOK_ALLOW_HAZARD_SURFACE, allow_hazard_surface)
 | 
						||
hook_event(HOOK_ON_LANGUAGE_CHANGED, on_language_changed)
 | 
						||
 | 
						||
for _, cheat in ipairs(sCheats) do
 | 
						||
    hook_mod_menu_checkbox(lang_string(cheat.names), false, update_cheat)
 | 
						||
end
 |