mirror of
https://github.com/Dingo-Shenanigans/ReSkate.git
synced 2026-10-24 17:06:17 +02:00
Hall of Meat (contrib/plugins/hall-of-meat) and grind exit triggers (contrib/plugins/grind-exits) are Lua plugins: the bail model, its Meat card, each map's best, the trigger rules, settings, console commands and menu panels are theirs, with their own checks that dingosdk_plugin_tests runs. What has to run in the game stays in core as plugin services: - every physics step of the skater (skater_physics, the physics_step event, permission events.physics); - the skater's x-ray (xray, xray_render, xray_skeleton; reskate.skater.xray and the draw handler's d:skeleton); - skate.'s bottom left HUD corner (hud_corner; reskate.hud.corner); - the game's slow motion, never in a session (game_speed; reskate.time.slow and speed, permission game.speed); - the side of the next pop out of a grind and pad controls kept from the game (grind_exit; reskate.skater.grind_exit, the grind_exit event, reskate.input.hide); - skate.'s own pictures by name (game_images; d:game_image), d:gradient and a font for drawn text. Removed: Extension/HallOfMeat, grind_exit_control and its commands, the HALL OF MEAT and GRIND EXITS add-on pages, home tile, hub and native menu rows, their menu models, and the hallofmeat and grindexit built-in commands.
184 lines
8.7 KiB
Lua
184 lines
8.7 KiB
Lua
-- Grind exit triggers: pick the side you pop out of a grind to with LT / RT, independently of the
|
|
-- trick and of the body's rotation (skate.'s own controls tie both to the left stick).
|
|
--
|
|
-- triggers.lua decides, each tick, which trigger picks the side and what the game must not see of
|
|
-- the pad (reskate.input.hide). At the pop ReSkate replaces only the sideways part of the game's
|
|
-- launch with the side asked for (reskate.skater.grind_exit): the game's own sideways speed when it
|
|
-- had one, mirrored to that side, else the game's usual 1.8 m/s, times the pop-out strength. Along
|
|
-- the rail, the pop's height, the trick, the flip and the rotation stay the game's.
|
|
local triggers = require("triggers")
|
|
|
|
local function setting(key, default, kind)
|
|
local value = reskate.storage.get(key)
|
|
if type(value) == kind then return value end
|
|
return default
|
|
end
|
|
local settings = {
|
|
on = setting("on", true, "boolean"),
|
|
toe_heel = setting("toe_heel", true, "boolean"), -- else left/right of travel
|
|
stance = setting("stance", "", "string"), -- "", "regular" or "goofy"
|
|
strength = setting("strength", 100, "number"), -- percent of the full sideways speed, 10 to 100
|
|
guard = setting("guard", true, "boolean"),
|
|
lean_guard = setting("lean_guard", true, "boolean"),
|
|
prewindow = setting("prewindow", 1, "number"), -- seconds a trigger may be pressed before the grind connects
|
|
}
|
|
local state = triggers.new()
|
|
local grinding = false
|
|
local wished = nil -- the side last asked of ReSkate ("toe", "heel", "left", "right"), or nil
|
|
local hidden_key = ""
|
|
local pops, applied = 0, 0
|
|
local last_pop = "none yet"
|
|
local why_not = nil -- ReSkate's refusal, when it refused
|
|
|
|
local function save(key, value)
|
|
settings[key] = value
|
|
reskate.storage.set(key, value)
|
|
end
|
|
local function wish(side)
|
|
if side == wished then return end
|
|
wished = side
|
|
local ok, why
|
|
if side then
|
|
local stance = settings.stance ~= "" and settings.stance or nil
|
|
ok, why = reskate.skater.grind_exit({side = side, stance = stance, strength = settings.strength / 100})
|
|
else
|
|
ok, why = reskate.skater.grind_exit(nil)
|
|
end
|
|
why_not = not ok and tostring(why) or nil
|
|
end
|
|
local function hide(h)
|
|
local key = tostring(h.left_trigger) .. tostring(h.right_trigger) .. tostring(h.left_x)
|
|
if key == hidden_key then return end
|
|
hidden_key = key
|
|
reskate.input.hide(h)
|
|
end
|
|
local function reset()
|
|
state = triggers.new()
|
|
wish(nil)
|
|
hide({})
|
|
end
|
|
|
|
reskate.on("skater_state", function(now) grinding = now == "grinding" end)
|
|
|
|
reskate.on("tick", function()
|
|
if not settings.on then return end
|
|
local now = reskate.time.now()
|
|
local pad = reskate.input.gamepad()
|
|
triggers.step(state, now, pad and pad.left_trigger, pad and pad.right_trigger, grinding, settings.prewindow * 1000)
|
|
hide(triggers.hidden(state, settings.guard, settings.lean_guard))
|
|
local trigger = triggers.chosen(state, now)
|
|
wish(trigger and triggers.side(trigger, settings.toe_heel) or nil)
|
|
end)
|
|
|
|
-- Each pop out of a grind, as it went.
|
|
reskate.on("grind_exit", function(pop)
|
|
pops += 1
|
|
if pop.applied then applied += 1 end
|
|
last_pop = pop.applied and string.format("%s of travel (%s), sideways %+.2f -> %+.2f m/s", pop.side, pop.basis or "-", pop.before, pop.after)
|
|
or pop.reason == "kept" and "the game already chose that side"
|
|
or pop.reason == "none" and "no trigger: the game's own exit"
|
|
or pop.reason == "slow" and "too slow to tell the rail's direction"
|
|
or "the launch did not match the skater's grind"
|
|
end)
|
|
|
|
-- ---- the switches ----------------------------------------------------------------------------
|
|
|
|
local function set_on(on)
|
|
if on == settings.on then return end
|
|
save("on", on)
|
|
if not on then reset() end
|
|
end
|
|
local function status()
|
|
local stance = settings.stance ~= "" and settings.stance or "NOT SET (grindexit stance goofy|regular)"
|
|
local text = string.format("%s. Sides: %s. Stance: %s. Pop-out strength %d%%. Grab guard %s, lean guard %s, pre-press window %.2f s. " ..
|
|
"Pops out of grinds seen: %d, sides set: %d. Last: %s.",
|
|
settings.on and "ON" or "off", settings.toe_heel and "LT toe / RT heel" or "LT left / RT right of travel", stance, settings.strength,
|
|
settings.guard and "on" or "off", settings.lean_guard and "on" or "off", settings.prewindow, pops, applied, last_pop)
|
|
if settings.on and settings.toe_heel and settings.stance == "" then text ..= " Until the stance is set, LT/RT are left/right of travel." end
|
|
if why_not then text ..= " ReSkate refused: " .. why_not end
|
|
return text
|
|
end
|
|
|
|
local function answer(args)
|
|
local function say(text) reskate.console.print("grindexit: " .. text) end
|
|
local verb, arg = args[1] or "status", args[2]
|
|
if verb == "status" then return say(status()) end
|
|
if verb == "exits" then
|
|
if arg == "on" or arg == "off" then set_on(arg == "on") end
|
|
return say(status())
|
|
end
|
|
if verb == "stance" then
|
|
if arg ~= "goofy" and arg ~= "regular" then return say("grindexit stance goofy|regular (your skater's stance in the game settings)") end
|
|
save("stance", arg)
|
|
wished = nil -- asked again with the stance
|
|
return say(status())
|
|
end
|
|
if verb == "sides" then
|
|
if arg ~= "toeheel" and arg ~= "travel" then return say("grindexit sides toeheel|travel") end
|
|
save("toe_heel", arg == "toeheel")
|
|
return say(status())
|
|
end
|
|
if verb == "strength" then
|
|
local value = tonumber(arg)
|
|
if not value or value ~= math.floor(value) or value < 10 or value > 100 then
|
|
return say("grindexit strength <10 to 100> (percent of the full pop-out to the side; 100 is the game's own)")
|
|
end
|
|
save("strength", value)
|
|
wished = nil
|
|
return say(status())
|
|
end
|
|
if verb == "guard" or verb == "leanguard" then
|
|
if arg ~= "on" and arg ~= "off" then return say("grindexit " .. verb .. " on|off") end
|
|
save(verb == "guard" and "guard" or "lean_guard", arg == "on")
|
|
return say(status())
|
|
end
|
|
if verb == "prewindow" then
|
|
local value = tonumber(arg)
|
|
if not value or value < 0 or value > 2 then return say("grindexit prewindow <0 to 2> (seconds a trigger may be pressed before the grind connects; 1)") end
|
|
save("prewindow", value)
|
|
return say(status())
|
|
end
|
|
if verb == "test" then
|
|
local passed, failures = require("tests").run()
|
|
for _, failure in failures do say("FAIL " .. failure) end
|
|
return say(string.format("%d passed, %d failed", passed, #failures))
|
|
end
|
|
say("grindexit exits on|off|status, stance goofy|regular, sides toeheel|travel, strength <10-100>, guard on|off, leanguard on|off, prewindow <s>, test")
|
|
end
|
|
reskate.console.command("grindexit", "Pick the side you pop out of a grind with LT / RT: exits on|off, stance, sides, strength, guard, leanguard",
|
|
answer)
|
|
|
|
reskate.menu.panel("Grind Exits", function(ui)
|
|
set_on(ui:toggle("on", "Grind exit triggers", settings.on))
|
|
ui:label("Press LT or RT while grinding (or up to a second before the grind connects) to pick the side you pop out to, then do any trick out of it. Keep the trigger held until you land.")
|
|
local mode = ui:dropdown("mode", "Input mode", {"Toe / Heel", "Left / Right"}, settings.toe_heel and 1 or 2)
|
|
if (mode == 1) ~= settings.toe_heel then save("toe_heel", mode == 1) end
|
|
if settings.toe_heel then
|
|
local stance = ui:dropdown("stance", "Your stance", {"Not set", "Regular", "Goofy"},
|
|
settings.stance == "regular" and 2 or settings.stance == "goofy" and 3 or 1)
|
|
local wanted = stance == 2 and "regular" or stance == 3 and "goofy" or ""
|
|
if wanted ~= settings.stance then
|
|
save("stance", wanted)
|
|
wished = nil
|
|
end
|
|
end
|
|
local strength = math.floor(ui:slider("strength", "Pop-out strength (%)", settings.strength, 10, 100) + 0.5)
|
|
if strength ~= settings.strength then
|
|
save("strength", strength)
|
|
wished = nil
|
|
end
|
|
ui:label("Lower it for rails next to a wall. 100% is the game's own full exit.")
|
|
if ui:toggle("guard", "Grab guard: the trigger that picked the side does not grab", settings.guard) ~= settings.guard then
|
|
save("guard", not settings.guard)
|
|
end
|
|
if ui:toggle("lean", "Lean guard: the left stick's left/right waits for the pop", settings.lean_guard) ~= settings.lean_guard then
|
|
save("lean_guard", not settings.lean_guard)
|
|
end
|
|
ui:label(string.format("Pops out of grinds seen: %d, sides set: %d. Last: %s.", pops, applied, last_pop))
|
|
end)
|
|
|
|
-- Its pops are heard from the start, before any trigger picks a side.
|
|
reskate.on("load", function() reskate.skater.grind_exit(nil) end)
|
|
reskate.on("unload", reset)
|
|
reskate.log("grind exits " .. (settings.on and "on" or "off") .. ": grindexit status")
|