Docs Quick code
Light, sky and weather
Give the player a lantern, change the sky, fog, weather and light from code, and put the level's own look back. With lots of ready-to-use recipes.
Four functions change how the world looks while the game runs. Everything fades smoothly, so a change feels like the world reacting, not a jump cut.
| Function | What it does |
|---|---|
player_light(kind, reach, color) |
The player carries a light |
sky(horizon, overhead, seconds) |
Fades the sky to new colors |
look(settings, seconds) |
Fades several things at once: sky, fog, mist, weather, light |
look_reset(seconds) |
Back to the level's own look (and its zones' looks) |
#The player's light
player_light("torch") -- lantern, torch, bright, cool, magic
player_light("lantern", 10) -- reaches 10 tiles
player_light("bright", 8, "#88ffcc") -- your own color
player_light("none") -- put it away
| Kind | Looks like |
|---|---|
"lantern" |
A warm glow with a gentle candle flicker (the default) |
"torch" |
Orange firelight that flickers |
"bright" |
A strong, steady white light |
"cool" |
A steady pale blue light |
"magic" |
A purple glow that slowly pulses |
"none" |
No light |
reach is how far it lights, in tiles: 6 if you leave it out, anything from 1 to 40. color
is a #rrggbb code; "" keeps the kind's own color. Calling it again swaps the light.
#The sky
sky("#7a3a9a", "#12061e") -- horizon, overhead: fades over 1.5 s
sky("#ff8040", "", 5) -- slow sunset; "" keeps the overhead color
The first color is the sky near the horizon, the second straight up. Leave one as "" to
keep it as it is. The last number is how many seconds the fade takes (1.5 if you leave it
out).
#The whole look at once
look({sky = "#203040", overhead = "#000010", fog = 0.04, fog_color = "#334455",
mist = 0.5, weather = "snow", light = "#8899cc", light_amount = 0.6}, 2)
look_reset() -- back to the level's own look
look() takes a table. Put in only what you want to change; everything else stays.
| Name | What it changes | Values |
|---|---|---|
sky (or horizon) |
The sky near the horizon | a color |
overhead |
The sky straight up | a color |
fog |
How thick the fog is | 0 (none) to about 0.1 (very thick) |
fog_color |
The fog's color | a color |
mist |
Low mist over the ground | 0 to 1 |
weather |
What falls or floats around the player | "none", "rain", "snow", "fireflies", "dust", "leaves" |
weather_amount |
How much of it | 0 to 1 |
light (or light_color) |
The color of the world's light | a color |
light_amount (or brightness) |
How bright the world's light is | about 0 (dark) to 1.5 |
Numbers and colors glide over the fade; the weather switches halfway through.
look_reset(seconds) drops every change your code made and fades back to the level's own
look. If the player is standing in a zone with its own look, that comes back too.
#Recipes
Copy these into a Code node and change the numbers. Each one says where the code goes.
#Pick up a torch
On a torch on the wall (Event: Player presses E):
give("Torch")
player_light("torch", 8)
popup("The torch lights up the walls around you.")
remove_self() -- it's in your hand now
#A lantern that runs out
On a lantern you press E to take. It lights for 60 seconds, then fades out.
-- Event: Player presses E
player_light("lantern", 9)
popup("You light the lantern. It won't last long...")
start_timer("lantern", 60)
wait(60)
player_light("lantern", 4) -- the flame gets small
popup("The lantern is flickering...")
wait(5)
player_light("none")
popup("The lantern goes out.")
#Walking into a cave
In a script with the Event Player enters a zone, set to the cave's zone:
look({light = "#202030", light_amount = 0.15, fog = 0.03, fog_color = "#05050a", weather = "none"}, 2)
if has("Torch") > 0 then
player_light("torch", 8)
else
popup("It's very dark in here. A torch would help.")
end
And a second script with Player leaves a zone, same zone:
look_reset(2)
player_light("none")
(A zone can also have its own look set in the editor without any code. Code is for when the look depends on something, like whether the player has a torch.)
#Sunset when the boss is beaten
On the boss (Event: It is destroyed):
banner("The Bone Queen falls")
sky("#ff8040", "#3a1850", 6)
look({light = "#ffb070", light_amount = 0.9, weather = "none"}, 6)
#A storm rolls in
popup("The wind picks up...")
look({sky = "#4a5260", overhead = "#20242c", light_amount = 0.5}, 8)
wait(8)
look({weather = "rain", weather_amount = 1, fog = 0.02, fog_color = "#3a4048"}, 4)
#Lightning
A bright flash, a dark sky snapping back, and a rumble. Run it during the storm:
every(rand(6, 12), function()
screen_effect("flash", 0.2, 1, "white")
sky("#d8e0ff", "", 0.05) -- the sky lights up...
wait(0.1)
sky("#4a5260", "", 0.3) -- ...and goes dark again
wait(rand(1, 3))
play("thunder") -- your own sound named "thunder"
shake(0.25, 0.8)
end)
#The light follows the clock
Run this when the level starts (Event: Player enters the level). It checks once a minute and changes the player's light and the weather with the time of day:
every(60, function()
if is_night() then
player_light("lantern", 7)
look({weather = "fireflies", weather_amount = 0.6}, 5)
else
player_light("none")
look_reset(5)
end
end)
#Jump to midnight
On a bed or a clock (Event: Player presses E). Needs the day & night cycle on:
local pick = choice("Sleep until...", ["Morning", "Midnight", "Stay awake"])
if pick == "Morning" then
set_hour(7)
look_reset(3)
elseif pick == "Midnight" then
set_hour(0)
sky("#0a0a30", "#000008", 3)
end
#A spooky room
On Player enters a zone, for a zone inside a haunted house (and look_reset(3) on Player leaves a zone):
look({light = "#6050a0", light_amount = 0.35, mist = 0.8, fog = 0.03, fog_color = "#1a1028"}, 3)
player_light("cool", 5)
play("creak")
#Under the water
On Player enters a zone, for a zone filling a lake:
look({sky = "#0a4060", overhead = "#022030", fog = 0.07, fog_color = "#0a5070",
light = "#60c0e0", light_amount = 0.6, weather = "none"}, 0.5)
player_light("cool", 6)
#A magic potion that lets you see in the dark
On a glowing mushroom you press E to eat (Event: Player presses E):
remove_self()
player_light("magic", 14, "#c080ff")
look({light = "#a080ff", light_amount = 1.2}, 1)
popup("Everything glows!")
wait(20)
look_reset(3)
player_light("none")
#Cycle the light color with a key
A script with the Event Player presses a key / mouse button, set to T. The light's
number is kept on the player (player.light_index), so it carries on from where it was:
local colors = ["#ffb060", "#80c0ff", "#80ffa0", "#ff80c0"]
player.light_index = ((player.light_index or -1) + 1) % #colors
player_light("bright", 8, colors[player.light_index])
#A sky picked from a Data table
Keep looks in a Data table called "Skies" with columns horizon, overhead and
weather, one row per mood (calm, storm, night…). Any script can then switch mood by name:
function set_mood(name)
local m = data("Skies")[name]
if m == nil then
warn("No sky called " .. name)
return
end
sky(m.horizon, m.overhead, 3)
look({weather = m.weather}, 3)
end
set_mood("storm")
Put set_mood in a library script and every level can use it with require.
#Wins and losses
-- Just before win(): a golden glow
look({sky = "#ffe080", overhead = "#ffb040", light = "#fff0c0", light_amount = 1.3}, 2)
-- When lives_left() reaches 0: everything goes gray and cold
look({sky = "#606060", overhead = "#303030", light = "#a0a0a0", light_amount = 0.4, weather = "none"}, 3)
#Darkness that follows a boss fight
On the boss arena's door (Event: Player presses E):
banner("Something stirs in the dark...")
look({light = "#401010", light_amount = 0.25, fog = 0.04, fog_color = "#200000"}, 3)
player_light("torch", 10)
on_message("boss beaten", function()
look_reset(4)
player_light("none")
end)
And in the boss's script, when it's destroyed: send("boss beaten").
#Tips
- Changes from code stay until you change them again or call
look_reset(). Going to another level starts that level with its own look. 0seconds changes things at once (good for the very start of a level).- If something should only change in one area, try a zone with its own look in the editor first. Use code when the change depends on what the player has done.
- Every fade can run while other code carries on; there's no need to
wait()for it unless you want the next step to start after it.