Copyable recipes
Each example below is a complete mod.lua, not an isolated API fragment. Create a new folder under Mods/S1Lua, paste one example into that folder as mod.lua, and change the mod ID before sharing your version.
Important
Every installed mod needs a unique lowercase id. Treat that ID as permanent once a save depends on it.
Pay a welcome bonus once per save
This mod gives the player $250 after a save loads, remembers that it paid the bonus, and requests a save. Restarting the game does not pay it twice.
local mod = s1.mod {
id = "s1lua.welcome-bonus",
name = "Welcome Bonus",
version = "1.0.0",
author = "S1Lua"
}
mod:on("game_loaded", function()
if mod:get("bonus_paid", false) then
return
end
mod:change_cash(250, true, true)
mod:set("bonus_paid", true)
mod:save()
s1.log("Paid the one-time $250 welcome bonus.")
end)
Change 250 to adjust the bonus. Keep the bonus_paid check unless you intentionally want to pay on every load.
Report player, money, and rank status
This read-only example shows how to handle player information that may not be ready yet and how to react to events. Its output appears in the MelonLoader console.
local mod = s1.mod {
id = "s1lua.status-watcher",
name = "Status Watcher",
version = "1.0.0",
author = "S1Lua"
}
mod:on("game_loaded", function()
local player = s1.player()
local progress = s1.progress()
local money = s1.money()
if player ~= nil then
s1.log("Current region: " .. player.region .. "; health: " .. player.health)
end
if progress ~= nil then
s1.log("Current rank: " .. progress.rank .. " tier " .. progress.tier)
end
s1.log("Cash on hand: " .. money.cash)
end)
mod:on("rank_up", function()
local progress = s1.progress()
if progress ~= nil then
s1.log("Rank advanced to " .. progress.rank .. " tier " .. progress.tier .. "!")
end
end)
mod:on("player_died", function()
s1.warn("The local player died.")
end)
mod:on("player_revived", function()
s1.log("The local player is back.")
end)
These information functions may return nil until the related part of the game is ready:
s1.player()returnsniluntil the local player exists;s1.progress()returnsniluntil progression exists;s1.money()returns numeric balances and uses zeros before the money manager exists.
Award XP for recycling trash
This example adds 5 XP for each trash object processed by the recycler. The normal cash reward remains unchanged.
local XP_PER_ITEM = 5
local mod = s1.mod {
id = "s1lua.recycle-for-xp",
name = "Recycle for XP",
version = "1.0.0",
author = "S1Lua"
}
mod:on("trash_recycled", function(item_count)
local xp = item_count * XP_PER_ITEM
if mod:add_xp(xp) then
s1.log("Recycled " .. item_count .. " trash item(s) and requested " .. xp .. " XP.")
else
s1.warn("Trash was recycled, but progression is not ready yet.")
end
end)
Change XP_PER_ITEM to tune the reward. A filled trash bag counts as one recycled object. XP awards work in single-player and for the lobby host.
Create a shop item
The starter example copies an existing item, changes how it appears, and adds it to suitable shops.
local mod = s1.mod {
id = "yourname.my-first-mod",
name = "My First Mod",
version = "1.0.0",
author = "Your Name"
}
mod:item {
id = "golden_cuke",
clone = "cuke",
name = "Golden Cuke",
description = "A suspiciously expensive energy drink.",
price = 250,
stack = 10,
shops = "compatible"
}
mod:on("game_loaded", function()
s1.log("My First Mod is ready!")
end)
Change one field at a time and restart the game. Keep id stable. You can freely change name, description, price, or stack while testing.
Split a mod into modules and delay work
The ModularTimer example loads a helper file from its own folder, then runs a function after the game loads.
local mod = s1.mod {
id = "bars.modular-timer",
name = "Modular Timer",
version = "1.0.0",
author = "Bars",
description = "Demonstrates safe modules and delayed callbacks."
}
local messages = mod:require("messages")
mod:on("game_loaded", function()
mod:after(1, function()
s1.log(messages.loaded())
end)
end)
Keep messages.lua beside mod.lua. For larger mods, use relative paths such as mod:require("features/reminders"); paths cannot leave the mod folder.
Combine recipes
Use one s1.mod { ... } declaration per mod.lua. To combine examples, keep the declaration from your own mod and copy only the mod:on(...) or mod:item { ... } blocks you need.
Next, use the Lua API reference to check accepted fields and event names. If the script does not load, the troubleshooting guide maps common console messages to fixes.