1.0 - General features

sol.main contains general features and utility functions that are global to the execution of the program, no matter if a game or some menus are running.

Functions of sol.main

sol.main.get_solarus_version()

Returns the current Solarus version.

The Solarus version includes three numbers: x.y.z, where x is the major version, y is the minor version and z is the patch version.

Changes of major and minor versions may introduce some incompatibilities in the Lua API. Patch versions are only for bug fixing and never introduce incompatibilities. See the migration guide for instructions about how to upgrade your quest to the latest version.

sol.main.get_quest_version()

Returns the version of the currently running quest as specified in the Quest Properties file.

sol.main.get_quest_format()

Returns the Solarus compatibility format of this quest.

This corresponds to a version of Solarus with major and minor version numbers (no patch number), for example "1.5".

sol.main.load_file(script_name)

Loads a Lua file (but does not run it).

This function is a replacement to the usual Lua function loadfile(). The difference is that it looks for a file in the quest tree (which may be a directory or an archive) and also in the quest write directory. The quest write directory is tried first.

Remarks
Keep in mind that Lua files, as all data files of your quest, may be located inside an archive instead of being regular files. Therefore, to run them, you cannot use usual Lua functions like loadfile() or dofile(). Use sol.main.load_file() and sol.main.do_file() instead to let Solarus determine how to locate and open the file.
Note however that require() can be used normally because it is a higher-level function. Indeed, a specific loader is automatically set by the engine so that require() looks in the archive if necessary and in the quest write directory. require() is the recommended way to load code from another file, because unlike sol.main.load_file() and sol.main.do_file(), it does not parses the file again every time you call it.

sol.main.do_file(script_name)

Loads and runs a Lua file into the current context.

This function is a replacement to the usual Lua function dofile(). The difference is that it looks for a file in the quest tree (which may be a directory or an archive) and also in the quest write directory. The quest write directory is tried first. The file must exist.

Use sol.main.load_file() explicitly if you need to check the existence of the file or to use parameters and return values.

Remarks
This function is equivalent to sol.main.load_file(script_name)().
require() is the recommended way to load code from another file, because unlike sol.main.load_file() and sol.main.do_file(), it does not parses the file again every time you call it.

sol.main.reset()

Resets the whole program after the current cycle. Lua will be entirely shut down and then initialized again.

sol.main.exit()

Exits the program after the current cycle.

sol.main.get_elapsed_time()

Returns the simulated time elapsed since Solarus was started.

This corresponds to real time, unless the system is too slow to play at normal speed.

Remarks
This time is not reset when you call sol.main.reset().

sol.main.get_quest_write_dir()

Returns the subdirectory where files specific to the quest are saved, like savegames and settings. The quest write directory is specified in your quest.dat file and may be changed dynamically with sol.main.set_quest_write_dir().

sol.main.set_quest_write_dir(quest_write_dir)

Changes the subdirectory where files specific to the quest are saved, like savegames and settings. Note that the quest write directory can already be specified in your quest.dat file. You usually don't have to call this function, unless you need to change it dynamically for some reason.

sol.main.load_settings([file_name])

Loads and applies the built-in settings from a file previously saved with sol.main.save_settings(). Settings from the file include user preferences such as the language and the audio volume.

Note that all these settings can already be modified individually with the Lua API, so you can either use this function or implement something more fitted to your needs.

A valid quest write directory must be set (in your quest.dat file or by calling sol.main.set_quest_write_dir()), otherwise this function generates a Lua error.

Remarks
When you launch a quest from the Solarus GUI, user preferences that are currently set in the menus of the GUI are automatically written to settings.dat before the quest starts and are automatically applied as soon as the quest starts.

sol.main.save_settings([file_name])

Saves the current built-in settings into a file. This file can be reloaded later with sol.main.load_settings() to restore the saved settings. Settings saved include user preferences such as the current language, and the current audio volume.

Note that all these settings can already be modified individually with the Lua API, so you can either use this function or implement something more fitted to your needs.

A valid quest write directory must be set (in your quest.dat file or by calling sol.main.set_quest_write_dir()), otherwise this function generates a Lua error.

Remarks
When you launch a quest from the Solarus GUI, user preferences that are currently set in the menus of the GUI are automatically written to settings.dat before the quest starts and are automatically applied as soon as the quest starts.

sol.main.get_distance(x1, y1, x2, y2)

Utility function that computes the distance in pixels between two points.

sol.main.get_angle(x1, y1, x2, y2)

Utility function that computes the angle in radians between the X axis and the specified vector.

sol.main.get_resource_ids(resource_type)

Returns an array of all resource elements IDs of the given type in the quest.

sol.main.get_type(value)

Returns the type name of a value.

This function is similar to the standard Lua function type(), except that for userdata known by Solarus, it returns the exact Solarus type name.

sol.main.get_metatable(type_name)

Returns the metatable of a Solarus userdata type.

This function is very powerful and should be used with care.

All userdata objects of a type share the same metatable. So there is a metatable for maps, a metatable for games, a metatable for enemies, etc.

The metatable of a type stores what is common to all instances of this type. For example, the metatable of the "enemy" type has a field "get_life" that is the Solarus function enemy:get_life() shared by all enemies.

Note that you can already get the metatable of any object with the standard Lua function getmetatable(object). This function does the same thing, except that you don't have to provide an existing object: you just provide a type name. This allows you do manipulate the metatable of a type before objects of this type start to exist, typically to set up things before a game is started.

You can use the metatable to add a function to all instances of a type. Thus, you can extend the Solarus API with your own functions. This also work for events (functions that the engine automatically calls when they exist). For example, you can easily provide a function add_overlay() to all your maps by defining it only once in the map metatable:

-- Somewhere in your main script, at initialization time:

local map_metatable = sol.main.get_metatable("map")
function map_metatable:add_overlay(image_file_name)
  -- Here, self is the map.
  self.overlay = sol.surface.create(image_file_name)
end

function map_metatable:on_draw(dst_surface)
  if self.overlay ~= nil then
    self.overlay:draw(dst_surface)
  end
end

-- Now, all your maps will have a function map:add_overlay() and an event
-- map:on_draw() that allows to draw an additional image above the map!

When you define a field in a metatable, everything acts like if you defined it in all existing and future instances of the type. However, an individual instance is still able to define a field with the same name. In this case, the instance has the priority: the field from the metatable is overridden.

Similarly, you can even remove (by assigning nil) or modify (by assigning a new value) any function of the Solarus API. We don't recommend to do that because introducing differences with the official API would be surprising for people who contribute to your game.

Remarks
If you are a Lua expert, you know that metatables are a very powerful mechanism. They are where the magic happens. Solarus uses metatables to do a lot of things, like allowing you to access userdata as tables. Therefore, you should never touch any metamethod (fields whose name starts with two underscores) in the metatable of a userdata type, in particular __index, __newindex and __gc. This may result in unspecified behavior, but most likely crashes.

sol.main.get_os()

Returns the name of the running OS. Possible values are : "Windows", "Mac OS X", "Linux", "iOS", "Android". If the correct OS name is not available, returns a string beginning with the text "Unknown".

Events of sol.main

Events are callback methods automatically called by the engine if you define them.

sol.main:on_started()

Called at the beginning of the program.

This function is called when Lua starts. In other words, the function is called when the program begins or after it was reset. In this function, you will typically start an initial menu like a title screen or a language selection screen. If you prefer, you can also start immediately a game.

sol.main:on_finished()

Called at the end of the program.

This function is called when Lua is about to be shut down, i.e., just before the program stops or is reset.

sol.main:on_update()

Called at each cycle of the program's main loop.

Remarks
This event is very powerful (because it is called at global level of the program) but it may be costly if you do heavy operations. Keep in mind that it is called at each cycle. You can usually use other callbacks instead to get notified of when an event happens. You can also use timers if you want to regularly check something.

sol.main:on_draw(dst_surface)

Called when the program's screen is redrawn.

At this point, the engine has already drawn the game (if a game is running) and has not drawn yet the menus of sol.main (if you have created menus on sol.main). Use this event if you want to draw some additional content.

sol.main:on_key_pressed(key, modifiers)

Called when the user presses a keyboard key.

Remarks
This event indicates the raw key pressed. If you want to know the corresponding character instead (if any), see sol.main:on_character_pressed().

sol.main:on_key_released(key, modifiers)

Called when the user releases a keyboard key.

sol.main:on_character_pressed(character)

Called when the user enters text.

Remarks
When a character key is pressed, two events are called: sol.main:on_key_pressed() (indicating the raw key) and sol.main:on_character_pressed() (indicating the utf-8 character). If you need to input text from the user, sol.main:on_character_pressed() is what you want because it considers the keyboard's layout and gives you international utf-8 strings.

sol.main:on_joypad_button_pressed(button)

Called when the user presses a joypad button.

sol.main:on_joypad_button_released(button)

Called when the user releases a joypad button.

sol.main:on_joypad_axis_moved(axis, state)

Called when the user moves a joypad axis.

sol.main:on_joypad_hat_moved(hat, direction8)

Called when the user moves a joypad hat.

sol.main:on_mouse_pressed(button, x, y)

Called when the user presses a mouse button.

sol.main:on_mouse_released(button, x, y)

Called when the user releases a mouse button.

sol.main:on_finger_pressed(finger, x, y, pressure)

Called when the user presses a finger.

sol.main:on_finger_released(finger, x, y, pressure)

Called when the user releases a finger.

sol.main:on_finger_moved(finger, x, y, dx, dy, pressure)

Called when the user moves a finger.